Harness Config#
agentpm.harness.json is the consumer-owned runtime configuration file for agentpm harness. It is optional, source-control friendly, and not packaged with the Agent.
If the file exists, version is required. Version 1 is strict: unknown fields are rejected except for open ID-keyed registries/maps and provider-specific model.options.
All relative paths resolve from the discovered workspace root, not from the config file's own directory.
Minimal Config#
{
"version": 1
}A missing config file is equivalent to version-1 defaults plus CLI, SDK, and environment values.
Complete Version-1 Reference#
This example is intentionally populated so every nested registry/mapping shape is concrete. Real workspaces should omit unused sections rather than emitting empty objects.
{
"version": 1,
"model": {
"provider": "openai",
"model": "gpt-5",
"options": {
"temperature": 0.2
}
},
"providers": {
"models": {
"company-model": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/company_model_provider.py"],
"cwd": ".",
"env": ["COMPANY_MODEL_API_KEY"],
"startup_timeout_ms": 15000,
"request_timeout_ms": 120000,
"restart": {
"max_attempts": 1,
"backoff_ms": 250
}
}
}
},
"embeddings": {
"example-4d": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/example_embedder.py"],
"env": []
}
}
}
},
"scopes": {
"user": "user-42",
"conversation": "incident-abc"
},
"runtime": {
"state_dir": ".agentpm-state",
"limits": {
"max_steps": 100,
"max_model_calls_per_phase": 24,
"max_tool_calls_per_phase": 16,
"max_actions_per_phase": 64,
"max_tool_call_repairs": 2,
"max_structured_output_repairs": 2,
"max_memory_operation_repairs": 2
}
},
"hooks": {
"implementations": {
"workspace-policy": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/hooks.py"],
"env": ["POLICY_SERVICE_TOKEN"]
}
}
},
"bindings": [
{
"hook": "before_model_request",
"implementation": "workspace-policy",
"failure_policy": "closed"
},
{
"hook": "before_tool_call",
"implementation": "workspace-policy",
"failure_policy": "closed"
},
{
"hook": "before_memory_write",
"implementation": "workspace-policy",
"failure_policy": "continue"
}
]
},
"knowledge": {
"runtimes": {
"pinecone-prod": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/pinecone_knowledge.py"],
"env": ["PINECONE_API_KEY"]
}
}
},
"packages": {
"@zack/agentpm-docs": {
"runtime": "pinecone-prod"
}
},
"embedding_matches": [
{
"match": {
"provider": "bring-your-own",
"model": "example-normalized-4d",
"dimensions": 4,
"normalized": true
},
"embedding_provider": "example-4d"
}
]
},
"memory": {
"write_review": {
"points": ["phase_end", "run_end"]
},
"local": {
"semantic": {
"embedding_provider": "example-4d",
"model": "example-normalized-4d",
"dimensions": 4
}
},
"runtimes": {
"postgres-prod": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/postgres_memory.py"],
"env": ["DATABASE_URL"]
}
}
},
"packages": {
"@zack/conversation-continuity": {
"runtime": "postgres-prod"
}
}
},
"mcp": {
"imports": {
"github": {
"transport": "stdio",
"command": "github-mcp-server",
"args": [],
"env": ["GITHUB_TOKEN"],
"scope": {
"mode": "phases",
"phases": ["assess", "execute"]
},
"tools": ["get_issue", "search_issues"],
"startup_timeout_ms": 15000,
"request_timeout_ms": 120000,
"restart": {
"max_attempts": 1,
"backoff_ms": 250
}
},
"company-search": {
"transport": "http",
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": {
"env": "COMPANY_MCP_AUTHORIZATION"
},
"X-Workspace": {
"value": "support"
}
},
"scope": {
"mode": "global"
}
}
},
"exports": {
"enabled": true,
"host": "127.0.0.1"
}
},
"approvals": {
"controller": {
"implementation": {
"type": "process",
"command": "python",
"args": ["runtime/approval_controller.py"],
"env": []
}
},
"timeout_ms": 300000
},
"trace": {
"enabled": true,
"level": "normal",
"content": "redacted"
},
"ui": {
"branding": {
"name": "AgentPM Harness",
"subtitle": null,
"accent": null
}
}
}Runtime Limits#
runtime.limits.max_steps is a consumer-owned Harness ceiling. It may tighten an installed Loop's authored loop.limits.max_steps, but it cannot loosen it. Harness uses the stricter value when both are present. For example, if the Loop package declares loop.limits.max_steps: 16 and the workspace config sets runtime.limits.max_steps: 100, the Run still stops at 16 steps.
Other Harness limits, such as model calls per phase, Tool calls per phase, total actions per phase, and repair counts, are runtime-only settings. Loop packages currently author only loop.limits.max_steps.
Implementation Descriptors#
Custom model providers, embedding providers, Hooks, Knowledge runtimes, Memory runtimes, and approval controllers use a shared implementation descriptor.
Process-backed:
{
"type": "process",
"command": "python",
"args": ["runtime/provider.py"],
"cwd": ".",
"env": ["PROVIDER_API_KEY"],
"startup_timeout_ms": 15000,
"request_timeout_ms": 120000,
"restart": {
"max_attempts": 1,
"backoff_ms": 250
}
}Host-backed:
{
"type": "host",
"request_timeout_ms": 120000
}process implementations speak the agentpm-service protocol over persistent stdin/stdout. host implementations are supplied by a connected machine/SDK client. Harness never silently replaces an unavailable configured implementation.
For runnable examples, start with @zack/harness-embedding-provider for a small EmbeddingProvider setup or @zack/harness-provider-lab for process-backed model, embedding, KnowledgeRuntime, and MemoryRuntime providers. The full index is in Example Project.
Model And Provider Config#
Built-in model providers are:
openaianthropicollama
Other model.provider values must match providers.models. Model IDs are open strings and are not enumerated by AgentPM. model.options is provider-specific JSON and must not contain secrets.
Hooks#
Version-1 Hook IDs:
before_model_requestbefore_tool_selectionbefore_tool_callbefore_knowledge_requestafter_knowledge_retrievalbefore_memory_readbefore_memory_writebefore_memory_operation
failure_policy is closed or continue and defaults to closed.
MCP#
mcp.imports brings external MCP servers into phase execution according to explicit scope. mcp.exports hosts Agent-authored outward MCP surfaces. Exported MCP surfaces are Session-owned, not Run-owned; calls to them do not become part of the active Run merely because their timing overlaps it. TUI and machine Sessions host exports while the Session is open; one-shot headless starts them only for the invocation and records final export state in the report.
Trace And Branding#
Trace defaults:
{
"trace": {
"enabled": true,
"level": "normal",
"content": "redacted"
}
}trace.level is minimal, normal, or verbose. trace.content is none, redacted, or full.
Branding is limited to name, subtitle, and accent. Harness does not provide arbitrary TUI layout/theme/plugin scripting.