Skip to content
This repository was archived by the owner on Jul 24, 2026. It is now read-only.
This repository was archived by the owner on Jul 24, 2026. It is now read-only.

Implement the agent spec as convoy's declaration contract #88

Description

@schickling-assistant

Goal

Implement the agent spec as convoy's declaration contract: one file per agent, agent-level fields as intent, child pty blocks as tasks, discovered by slurping the catalog.

Today convoy reads a TOML catalog at <net>/catalog/<identity>.toml and writes a separate .convoy/pty.toml. The spec unifies those into one file and adds the pieces that make declared agents durable.

This is a tracking issue for the work; individual pieces can land separately.

Why now

Two properties we want depend on this, and neither is reachable with the current shape.

Declared, stable identity. Names generated per launch resolve to fresh, empty context storage on every restart. Anything that externalizes state to context/now.md can therefore never read its own predecessor's writing. A declared identity in a catalog file is what makes cold-boot continuity possible at all.

Restart convergence. Once identity is stable and context is external, a session can be killed at any moment and a fresh one converges on the same goal. That turns crash recovery into a testable property rather than an aspiration.

Work

1. Catalog in the spec format

Read agent specs per the spec — KDL, TOML, and JSON with identical semantics. Discovery slurps catalog/**/*.{kdl,toml,json} and keeps whatever is an agent spec; identity comes from content, with path segments supplying defaults and a path↔content mismatch a warning.

Replaces the split between the catalog entry and .convoy/pty.toml.

2. Identity validation at declare time

convoy add currently checks only truthiness and bypasses both the parser and preflight, so nothing validates identity on the way in. This matters because convoy's accepted charset and smalltalk's disagree: worker_fodfix passes convoy's launch check and is rejected by the bus. A name that declares cleanly and then cannot be written is the worst failure ordering.

Validate at declare time against one grammar — charset, length, reserved words, uniqueness scope. Length has a real bound: pty keys its socket on ${name}.sock, so identity length is constrained by socket path limits, not just aesthetics.

3. convoy rename

Rename must move the catalog entry and the whole bus folder — context/, context/decisions/, archive/, inbox/, status — and leave a redirect tombstone at the old identity so in-flight messages and stale peer references resolve rather than failing.

This is load-bearing rather than convenience. If identity must be a meaningful declared name, the cost of choosing one is only acceptable when a wrong choice is cheaply correctable. Without rename-preserving-continuity, changing a name orphans everything the agent externalized.

Tombstones accumulate and want a retention rule.

4. Launch through an external command

Convoy currently execs the harness binary directly (exec claude …). Deployments that wrap their harness — for credential selection, persona projection, policy gates, telemetry — are bypassed entirely, so a convoy-managed session runs outside the boundary every other session in that deployment runs inside.

An optional bin on the agent spec, used in place of the bare harness name when deriving the command, resolves this without convoy needing to know what the wrapper does. It also sidesteps the closed Harness = "claude" | "codex" union for deployments running other harnesses.

5. up --once should pre-trust

convoy up --once does not pre-trust the agent directory, so the harness sits at its trust prompt forever and the one-shot path is not usable headlessly. Hosted convoy up does pre-trust. Worth aligning.

6. Refuse context/ under counter-named identities

A <role>-<n> counter discriminator looks safe but isn't: the counter re-derives only within one parent's lifetime, so a restart renumbers peers and an agent can silently inherit a stranger's context/now.md. Reading another agent's durable state as your own is a bad failure to leave available.

Suggest convoy refuse to create context/ under a counter-named folder, making the unsafe case structurally impossible rather than discouraged. Meaningful discriminators stay fine — in practice most already are.

7. convoy run

There is no convoy run today, so there's no supported path for an ad-hoc session that isn't a declared catalog member. Deployments retiring their own per-account launcher aliases need somewhere for one-off sessions to go.

Related

Items 1–3 are the spine; 4 unblocks wrapped deployments; 5–7 are smaller and independent. Happy to take any of them, and would rather agree the shape of 2 and 3 before writing code, since both change existing behaviour.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions