Getting startedCreate your first initiativeConnect version controlInvite your teamPlan today's work
OverviewQuickstartHarness manifestACP contractDocuments & toolsMCP toolsDistributeRun & monitorBuild cloud agentAgent sessionsReferenceLimits & securityTroubleshooting
DocsAPI Reference

Main

  • Home
  • About
  • Pricing
  • Changelog
  • Docs

Features

  • Roadmap
  • Boards
  • Triage
  • Workflows & agents
  • Progress
  • Insights
  • CLI
  • Integrations

Solutions

  • Startups
  • Dev shops / agencies
  • Software teams
  • Internal IT & platform teams

Alternatives

  • vs Jira
  • vs Linear
  • vs Asana
  • vs Monday.com
  • vs ClickUp
  • vs Notion

Company

  • Blog
  • Security
  • Log in
  • Sign up
  • Terms of Use
  • Privacy Policy

Resources

  • Docs
  • Community
  • Support
  • API reference
  • Desktop app
  • SDK
  • Vault
  • QR code generator

© 2026 One Horizon. All rights reserved

FacebookInstagramThreadsXTikTokYouTubeMedium


The ACP contract

The worker is a headless Agent Client Protocol client; your harness is an ACP agent. Everything on this page is standard ACP unless marked as a One Horizon behavior. An agent that implements this contract can run every workflow mode unless its manifest lists the mode in unsupportedModes.

Turn lifecycle

sequenceDiagram
  participant H as Worker (ACP client)
  participant A as Your agent (ACP agent)
  H->>A: spawn process (manifest command)
  H->>A: initialize (capabilities)
  A->>H: capabilities (loadSession?, mcp transports)
  H->>A: session/new (cwd = task worktree, mcpServers = [One Horizon tools])
  A->>H: sessionId
  H->>A: session/prompt (content blocks, _meta context)
  A-->>H: session/update × n (messages, thoughts, plans, tool calls, usage)
  A->>H: stopReason
  H->>A: terminate, process exits
Sequence diagram
  • One process per turn. The host spawns your command, runs one session with one prompt turn, and terminates the process after the stop reason. If your agent advertises sessionCapabilities.resume or loadSession, the host uses it for multi-turn continuity (feedback loops, resume-after-input) instead of replaying context into a fresh session, which makes retries cheaper.
  • Timeouts are the host's. A turn that exceeds the configured turn timeout, or emits nothing for the stall window, is cancelled (session/cancel) and the process terminated. Do not build your own watchdog; do keep updates flowing while you work.

What arrives in the prompt

session/prompt carries ordered content blocks:

  1. Trusted policy: platform instructions as an <instructions trust="trusted"> markdown block (AgentTrustedInstructionsV1) with policy rules, workflow routing facts, and agent/worker custom instructions. _meta["onehorizon.ai"].trust = "trusted".
  2. Workflow instructions: the step's operating instructions, also trust = "trusted".
  3. Untrusted context: task title, description, comments, user prompt, and resume input as a <context trust="untrusted"> markdown block (AgentTaskContextV1). trust = "untrusted".
  4. Resources: images or files referenced by the task, as standard resource blocks.

An ACP agent that ignores _meta still works, because it sees the blocks in the same order and framing that built-in harnesses receive. An agent that reads the trust markers can map trusted blocks to its system prompt and untrusted blocks to user content.

_meta["onehorizon.ai"] appears in two places, each a versioned, schema-validated shape:

  • Per content block, on every text block in the prompt: trust, and taskMode on the untrusted block only. one harness dev and the harness conformance check add synthetic: true to this block on their generated turns; real turns never set it.
  • Once on session/new (and session/load/session/resume): taskId, workspaceId, ownerUserId, sessionId, workflowRunId, workflowStepId, workflowBranch, attempt (the workflow step's server-owned pass number), harnessAttempt (a worker-local counter for crash recovery and provider retries of this same session, distinct from attempt), taskMode, artifactsDir, linkedDocumentIds, and labeled goals/products/skills ({ labelId, name } pairs). Every field is present on every turn, with absent data as an explicit null, so the shape is the same whether or not the turn is workflow-linked. This is the only structured channel for turn context; a scripted agent that does not parse prose should read it instead of the prompt text.

The shapes below are generated from the schema the worker validates against before sending.

Per-block _meta:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "version": {
      "type": "number",
      "const": 1
    },
    "trust": {
      "type": "string",
      "enum": [
        "trusted",
        "untrusted"
      ]
    },
    "taskMode": {
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "plan",
            "code",
            "review",
            "research"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "synthetic": {
      "type": "boolean"
    }
  },
  "required": [
    "version",
    "trust",
    "taskMode"
  ],
  "additionalProperties": false
}

Session-level _meta:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "version": {
      "type": "number",
      "const": 1
    },
    "taskId": {
      "type": "string"
    },
    "workspaceId": {
      "type": "string"
    },
    "ownerUserId": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "sessionId": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "workflowRunId": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "workflowStepId": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "workflowBranch": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "attempt": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ]
    },
    "runtimeAttempt": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ]
    },
    "taskMode": {
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "plan",
            "code",
            "review",
            "research"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "artifactsDir": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "linkedDocumentIds": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "goals": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "labelId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "labelId",
          "name"
        ],
        "additionalProperties": false
      }
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "labelId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "labelId",
          "name"
        ],
        "additionalProperties": false
      }
    },
    "skills": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "labelId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "labelId",
          "name"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [
    "version",
    "taskId",
    "workspaceId",
    "ownerUserId",
    "sessionId",
    "workflowRunId",
    "workflowStepId",
    "workflowBranch",
    "attempt",
    "runtimeAttempt",
    "taskMode",
    "artifactsDir",
    "linkedDocumentIds",
    "goals",
    "products",
    "skills"
  ],
  "additionalProperties": false
}

Trusted policy text block (<instructions trust="trusted">):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "version": {
      "type": "number",
      "const": 1
    },
    "policyRules": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "workflowDocumentsGuidance": {
      "type": "string"
    },
    "workflowRun": {
      "type": "object",
      "properties": {
        "attemptNumber": {
          "type": "number"
        },
        "taskMode": {
          "type": "string",
          "enum": [
            "plan",
            "code",
            "review",
            "research",
            "resolve conflicts"
          ]
        },
        "taskModeGuidance": {
          "type": "string"
        },
        "stageContract": {
          "type": "object",
          "properties": {
            "currentStage": {
              "type": "string"
            },
            "objective": {
              "type": "string"
            },
            "inputsReviewSubject": {
              "type": "string"
            },
            "expectationBoundary": {
              "type": "string"
            },
            "outcomeDiscipline": {
              "type": "string"
            }
          },
          "required": [
            "currentStage",
            "objective",
            "inputsReviewSubject",
            "expectationBoundary",
            "outcomeDiscipline"
          ],
          "additionalProperties": false
        },
        "expectedInputsGuidance": {
          "type": "string"
        },
        "workflowBranch": {
          "type": "string"
        },
        "nextStep": {
          "type": "object",
          "properties": {
            "terminal": {
              "type": "boolean"
            },
            "nextStepName": {
              "type": "string"
            },
            "nextStepType": {
              "type": "string",
              "enum": [
                "agent",
                "human_gate",
                "unknown"
              ]
            },
            "guidance": {
              "type": "string"
            }
          },
          "required": [
            "terminal",
            "guidance"
          ],
          "additionalProperties": false
        },
        "verdictRoutesGuidance": {
          "type": "string"
        },
        "finalReviewPassGuidance": {
          "type": "string"
        },
        "completedGateDecisions": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "stepName": {
                "type": "string"
              },
              "decision": {
                "type": "string",
                "enum": [
                  "approve",
                  "reject",
                  "feedback",
                  "reassign"
                ]
              },
              "actorName": {
                "type": "string"
              },
              "decidedAt": {
                "type": "string"
              }
            },
            "required": [
              "stepName",
              "decision",
              "decidedAt"
            ],
            "additionalProperties": false
          }
        }
      },
      "required": [
        "attemptNumber",
        "taskModeGuidance",
        "stageContract"
      ],
      "additionalProperties": false
    },
    "agentCustomInstructions": {
      "type": "string"
    },
    "workerCustomInstructions": {
      "type": "string"
    }
  },
  "required": [
    "version",
    "policyRules"
  ],
  "additionalProperties": false
}

Untrusted task context text block (<context trust="untrusted">):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "version": {
      "type": "number",
      "const": 1
    },
    "taskId": {
      "type": "string"
    },
    "title": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "workspaceId": {
      "type": "string"
    },
    "providerName": {
      "type": "string"
    },
    "providerUseCase": {
      "type": "string"
    },
    "parentInitiative": {
      "type": "object",
      "properties": {
        "identifier": {
          "type": "string"
        },
        "title": {
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "identifier"
      ],
      "additionalProperties": false
    },
    "goals": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "products": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "skills": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "comments": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/__schema0"
      }
    },
    "linkedDocuments": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "requirement",
              "task",
              "design_doc",
              "spec",
              "research",
              "review",
              "notes"
            ]
          },
          "excerpt": {
            "type": "string"
          }
        },
        "required": [
          "documentId",
          "title",
          "type",
          "excerpt"
        ],
        "additionalProperties": false
      }
    },
    "sessionPrompt": {
      "type": "string"
    },
    "workflowHandoffNote": {
      "type": "string"
    }
  },
  "required": [
    "version",
    "taskId",
    "title",
    "comments",
    "linkedDocuments"
  ],
  "additionalProperties": false,
  "$defs": {
    "__schema0": {
      "type": "object",
      "properties": {
        "author": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ]
        },
        "content": {
          "type": "string"
        },
        "createdAt": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ]
        },
        "replies": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/__schema0"
          }
        }
      },
      "required": [
        "content",
        "replies"
      ],
      "additionalProperties": false
    }
  }
}

Trust boundaries

Untrusted blocks are task data, not instructions. Your agent must not let untrusted content override trusted policy, no matter how convincingly a task description asks. If your framework has a system/user message distinction, use it.

Headless behaviors

ACP grew up inside editors with a human present. The worker has no human at the keyboard, so:

  • session/request_permission is answered immediately, never by a human. The host resolves the requesting tool from the full toolCall payload and its correlated tool_call/tool_call_update. A request it can confidently match to the injected one_platform server, including Vibe's one_platform_<tool> identifier form, gets a one-time allow, so a default-Ask permission mode does not block required platform tools. This is not a sandbox: your own tools, external MCP servers, and ambiguous matches fall back to the agent's configured permission policy, and an unresolvable identity is cancelled rather than approved. For genuine human input, finish the turn; the awaiting-input flow handles the round-trip and resumes you.
  • Client fs/terminal capabilities are not offered. You run in the task worktree with the user's OS permissions; use your own process's filesystem and shell access directly. cwd from session/new is the workspace boundary.
  • Unknown extension methods you send are answered per spec (-32601); unknown notifications are ignored.

What the host does with your updates

Your session/updateWhere it lands
agent_message_chunkLive activity on the task, sentence-buffered
agent_thought_chunkCollapsed reasoning in the session transcript
planThe plan panel on the run; keep it current
tool_call / tool_call_updateSession transcript detail; routine lifecycle updates are retained for permission correlation but are not persisted as user-facing activity
usage_updateContext size and cumulative cost on the dashboards. It carries no token counts
usage on the session/prompt responseInput, output, and total tokens for the run. Send the counts for that turn only; One Horizon adds the turns up. inputTokens is read without cache and outputTokens without reasoning: cachedReadTokens and cachedWriteTokens are added to input, thoughtTokens to output, and the total is input plus output. Your own totalTokens is ignored. A missing or malformed usage shows "—", never 0, and never fails the turn
config_option_update, and configOptions on session/new, session/load, and session/resumeThe model shown for the run: the currentValue of the select option in the model category. The latest value wins. The model provider shown is your manifest name

Emit meaningfully, not constantly: updates are your only voice in the product, and silence past the stall window looks like a hang.

Outcome mapping

stopReasonSession outcome
end_turnSucceeded, unless the task mode required a verdict or artifact that never arrived (see below)
refusalAwaiting input: your stated reason is shown to the user as a question; when they clarify, the session resumes. Refusals are never auto-retried
max_tokens, max_turn_requestsFailed, retryable: the workflow's retry policy and pass accounting apply; repeated budget failures trigger the stall notification
cancelledWhatever the host requested (user cancel, timeout, shutdown)
Process exit without a stop reasonFailed, protocol violation logged with your stderr

Mode contracts (One Horizon behavior): plan and research turns must write their declared artifact; review turns must call report_workflow_verdict; execute turns must call report_result, which every other successful mode should also call. The injected MCP tools are scoped to the active step.

Conformance

one harness dev validates all of the above on every local turn and prints violations inline. Before distributing, run every mode you declare in the manifest:

one harness dev --mode codeone harness dev --mode plan && one harness dev --mode review   # if declared

Per-mode dev runs do not change which modes your harness is offered.


PreviousHarness manifestNextDocuments & tools

MCP tools

Every MCP tool the worker can register for a turn, generated straight from the harness tool catalog.

Overview

Plug any ACP-compatible agent into the worker. One Horizon handles auth, sessions, tools, and monitoring; you build the agent.

Harness manifest

The one.json reference: everything the worker needs to install, verify, and launch your agent.

Troubleshooting

Fix install, discovery, auth, protocol, git, and operations failures for custom harnesses, plus the cloud agent API lifecycle.

  • Turn lifecycle
  • What arrives in the prompt
  • Headless behaviors
  • What the host does with your updates
  • Outcome mapping
  • Conformance
  • Back to top