Crystal Lattice
Plugin-driven agent platform

For people who outgrow
one-size-fits-all agents.

Crystal Lattice is a model-native agent platform: the harness changes around the model, including its system message, tool schema, request behavior, provider-native state, and UI controls. Built-in plugins provide Codex, Claude, Gemini, Qwen, Kimi, and Grok-style defaults, and your config can replace them.

$ curl -fsSL https://download.crystallattice.dev/crystal-lattice-cli/install.sh | bash
or pipx install crystal-lattice-cli

Built-in model-family harnesses

Codex-style toolsClaude-style workflowsGemini-oriented toolsQwen-oriented toolsKimi-oriented toolsGrok-oriented tools

Computer to phone

Start at your desk. Keep going from your phone.

Start Crystal Lattice in the project folder where you want the agent to work. The terminal UI can stay open, but the work is not trapped there: the app UIs can open the same sessions and watch responses stream.

On the same Wi-Fi, Crystal Lattice Control can find your computer automatically. Choose Automatic Discovery, select your computer, and continue the same workspace from your phone.

Automatic discovery uses the local network. If your phone is outside that network, use the bridge section below.

Run the local workspace

01

Install the CLI

bash — 80×24
curl -fsSL https://download.crystallattice.dev/crystal-lattice-cli/install.sh | bash
02

Start Crystal Lattice with local discovery

bash — 80×24
mkdir -p ~/crystal-lattice-demo
cd ~/crystal-lattice-demo
crystal-lattice \
--server \
--console \
--config-local \
--host 0.0.0.0 \
--port 9000 \
--enable-bonjour
03

Open the mobile app

Open Crystal Lattice Control, choose Automatic Discovery, and select your computer.

connectionDiagram

Show computer runtime on the left and terminal, desktop app, mobile app, and custom UI connected to the same sessions.

Outside your local network

Pair through a self-hosted bridge

Hosted bridge service is coming soon. Today, when your phone is not on the same network as your computer, deploy your own bridge and pair through it.

The bridge gives Crystal Lattice clients a way to reconnect from outside the local network. Local bridge hosting is useful for development and testing, but production use should deploy the bridge somewhere reachable.

Deploy the bridge on AWS

01

Create the bridge deployment

bash — 80×24
ALLOW_AWS_DEPLOY=1 deploy/aws-ec2/build.sh \
--profile secure \
--stack-name crystal-lattice-bridge \
--region us-east-1
ALLOW_AWS_DEPLOY=1 deploy/aws-ec2/up.sh \
--profile secure \
--stack-name crystal-lattice-bridge \
--region us-east-1
02

Start Crystal Lattice with the bridge URL

bash — 80×24
crystal-lattice \
--server \
--console \
--config-local \
--host 0.0.0.0 \
--port 9000 \
--bridge-url wss://<your-cloudfront-domain>/ws/websocket
03

Pair from the phone

Open Crystal Lattice Control, choose Bridge Service, enter the bridge URL, select your computer, and enter the pairing code.

bridgeDiagram

Show phone -> bridge -> user's computer, with pairing code callout.

Model-native harnesses

Stop forcing every model through the same prompt and tools.

Model-native means Crystal Lattice changes the harness around the model: system message, tool schema, request behavior, provider-native state, and UI controls. The built-in defaults do this with plugins, and those plugins can be replaced.

Model familyBuilt-in harnessWhat changes
Codex / GPT coding modelscodex-toolsCodex-style shell tools, apply patch semantics, skills block, model-family system instructions.
Claudeclaude-toolsClaude-oriented tool schema and workflow conventions.
Geminigemini-tools + compaction pluginsGemini-oriented system message and tool behavior, optional compaction flow.
Qwenqwen-toolsQwen-oriented tool and instruction style.
Kimikimi-toolsKimi-oriented tools and prompt behavior.
Grokgrok-toolsGrok-oriented tools and request behavior.
OpenAI Responsesopenai_responsesResponses-native reasoning, usage/cost metadata, attachments, prompt caching, native compaction.
OpenRouteropenrouterOpenRouter model routing, reasoning/web/image extensions depending on provider path.

Native provider features

Provider-specific behavior can become real UI.

Some capabilities are not generic chat settings. Reasoning effort, verbosity, web search, prompt caching, native compaction, attachment handling, usage, and cost metadata depend on the provider path.

Crystal Lattice lets provider and feature plugins expose those controls and outputs directly to the UI, so native behavior is visible instead of hidden behind a generic wrapper.

screenshot

placeholder-needed

Reasoning and verbosity

Expose model-specific controls when the provider supports them.

screenshot

placeholder-needed

Web search and citations

Show search/citation behavior through provider extensions where available.

screenshot

placeholder-needed

Prompt caching and compaction

Keep long sessions practical with provider-native cache and compaction controls.

screenshot

placeholder-needed

Usage, cost, and attachments

Surface metadata, generated assets, and attachment handling in the UI.

Everything is replaceable

Serious users eventually disagree with the harness.

Crystal Lattice treats that as normal. Providers, provider extensions, features, tools, application actions, session behavior, and UI elements are all plugin surfaces.

The built-in plugins give you useful defaults. Your own plugins can replace the parts your workflow disagrees with, and config can point at those plugins without waiting for upstream approval.

Code examples are illustrative placeholders, not final API.

Provider

Add native support for a model API.

python
# Placeholder example, not final API.
class MyProvider:
    name = "my_provider"

    def to_native_messages(self, messages, state, *, context=None):
        return convert_to_my_api(messages)

    def stream_api(self, native_messages, state):
        yield from call_my_model(native_messages, state)

Provider extension

Surface provider metadata, reasoning, citations, or UI fields.

python
# Placeholder example, not final API.
class UsageFooter:
    name = "usage_footer"

    def finalize(self, final_messages, native_messages, state):
        return add_usage_metadata(final_messages, state)

    def get_ui_elements(self, config, context=None):
        return [
            {"ui_type": "message_footer", "data": "metadata.total_cost"}
        ]

Feature

Transform context, request behavior, or final messages.

python
# Placeholder example, not final API.
class ProjectContext:
    name = "project_context"

    def to_native_messages(self, messages, native_messages, state):
        return inject_project_context(native_messages)

Tool

Expose Python, Node, Bash, or MCP-backed capabilities.

python
# Placeholder example, not final API.
class SearchTickets:
    name = "search_tickets"

    def get_tool_schemas(self, state):
        return [ticket_search_schema]

    def execute_tool(self, tool_name, payload, state):
        return search_linear_or_jira(payload)

Application plugin

Add session-level workflow actions.

python
# Placeholder example, not final API.
class CreateReleaseNotes:
    name = "release_notes"

    def get_actions(self, state):
        return [
            {
                "id": "release_notes.create",
                "label": "Create release notes",
            }
        ]

    def execute_action(self, app, action_id, params, context, state):
        return create_release_notes(app, params)

UI schema

Render settings and actions in app UIs without hardcoding them.

python
# Placeholder example, not final API.
def get_ui_elements(self, config, context=None):
    return [
        {
            "ui_type": "session_action",
            "label": "Sync down",
            "action_id": "cloud.sync_down",
        },
        {
            "type": "select",
            "key": "reasoning_effort",
            "label": "Reasoning effort",
        },
    ]

Session workbench

Treat sessions as workspaces, not disposable chats.

Agent work is more than a transcript. Built-in session plugins turn conversations into durable workspaces with titles, pinned state, summaries, snapshots, attachments, ordering, and session actions.

The workbench is plugin-driven too: built-in plugins provide the default behavior, and your own plugins can add or replace workflow actions.

placeholder-needed

/session-list-workbench.png

Session list

Titles, pinned state, ordering, message counts, and timestamps.

placeholder-needed

/chat-actions-workbench.png

Chat actions

Message and session actions exposed by plugins.

placeholder-needed

/session-snapshots-workbench.png

Snapshots

Create, inspect, select, and restore session checkpoints.

placeholder-needed

/session-attachments-workbench.png

Attachments

Preserve generated assets and session-owned files.

placeholder-needed

/session-settings-plugins.png

Settings and plugins

Per-session controls from plugin UI schema.

Plugin authoring

Ask an agent to plan the plugin.

A user-owned plugin workflow still needs product polish, but the design goal is straightforward: inspect the docs, pick the right plugin type, copy the closest template, write tests, and load the plugin from config.

prompt
I want to build a Crystal Lattice plugin.

Please inspect the plugin documentation in this repository, especially:
- plugins/docs/index.md
- plugins/docs/tool-plugins.md
- plugins/docs/application-plugins.md
- plugins/docs/provider-plugins.md
- plugins/docs/provider-extensions.md
- plugins/docs/feature-plugins.md
- plugins/docs/ui-elements.md
- plugins/docs/plugin-packaging-and-loading.md

Goal:
Create a plugin that [describe what I want].

Please:
1. Identify whether this should be a provider, provider extension, feature, tool, or application plugin.
2. Find the closest existing plugin or template to copy from.
3. Explain what UI, if any, the plugin should expose.
4. Propose the file layout.
5. Draft an implementation plan.
6. Tell me what tests should be added before coding.
json
{
  "plugins": [
    "path:./plugins/my-custom-plugin"
  ]
}

Python SDK

Automate the same harness with Python.

When the work becomes repetitive, use the same configured agents and plugins from Python. The example below sketches a short sales-letter workflow over a CSV of leads.

The final webpage should verify this against the current SDK and may add a small helper if the public API needs a simpler "run until final" path.

sdk-api-needs-verification
python
import pandas as pd
from agent_app import AgentApplication

app = AgentApplication.from_config("./.crystal/config.json")
leads = pd.read_csv("leads.csv")

def draft(row):
    session = app.create_session(agent_id="codex-openrouter")
    app.add_message(
        session.session_id,
        "user",
        f"""
        Write a concise first sales email.

        Name: {row.name}
        Role: {row.role}
        Company: {row.company}
        Notes: {row.notes}
        """,
    )
    result = app.run_until_final(session.session_id)
    return result.content

leads["draft"] = leads.apply(draft, axis=1)
leads.to_csv("drafts.csv", index=False)

Use the harness you can inspect and replace.

Start with built-in model-family plugins, run Crystal Lattice on your computer, continue from phone or app UI, and replace the parts of the harness your workflow disagrees with.