@agentproto/corpus-cli 0.1.0-alpha.6 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# AIP-52 — Harness · Implementer Guide
|
|
2
|
+
|
|
3
|
+
> **Status:** Draft
|
|
4
|
+
> **Schema:** `HARNESS.schema.json`
|
|
5
|
+
> **Canonical runtime:** `@mastra/core/harness` (Mastra's `Harness` class)
|
|
6
|
+
|
|
7
|
+
## What is a Harness?
|
|
8
|
+
|
|
9
|
+
A Harness is a **stateful, multi-mode conversational shell**. Where an AIP-42 Agent is
|
|
10
|
+
a single-purpose inference unit, a Harness composes multiple agents into an orchestrated
|
|
11
|
+
shell that can:
|
|
12
|
+
|
|
13
|
+
- Switch between **modes** (e.g. plan → execute → review) with distinct agents, tools,
|
|
14
|
+
and permission rules per mode.
|
|
15
|
+
- Hold a **typed conversation state** (`stateSchema` + `initialState`) that persists
|
|
16
|
+
across turns and is visible to all modes.
|
|
17
|
+
- Spawn **subagents** via the built-in `subagent` tool (forked or isolated thread).
|
|
18
|
+
- Gate tool calls via **tool-approval gates** (`permissions`, `submit_plan` builtin).
|
|
19
|
+
- Run **heartbeat handlers** in the background (OM reflector, progress reporter, etc.).
|
|
20
|
+
|
|
21
|
+
A Harness IS NOT a subtype of AIP-42. Agents are referenced _from_ harness manifests
|
|
22
|
+
via `$resolver` / `$ref`; the harness is the orchestrator, not the agent itself.
|
|
23
|
+
|
|
24
|
+
## Filesystem layout
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
.harness/
|
|
28
|
+
<slug>.md ← one manifest per harness (YAML frontmatter + prose body)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The markdown body (after the frontmatter block) is purely documentary — it is not
|
|
32
|
+
parsed by the runtime.
|
|
33
|
+
|
|
34
|
+
## Manifest shape
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
---
|
|
38
|
+
spec: harness/v1
|
|
39
|
+
id: my-harness
|
|
40
|
+
name: My Harness
|
|
41
|
+
version: 1.0.0
|
|
42
|
+
description: One-sentence description.
|
|
43
|
+
|
|
44
|
+
storage:
|
|
45
|
+
$resolver: mastra.storage.composite # must resolve to MastraCompositeStore
|
|
46
|
+
|
|
47
|
+
modes:
|
|
48
|
+
- id: plan
|
|
49
|
+
default: true
|
|
50
|
+
name: Plan
|
|
51
|
+
agent: { $resolver: my-agent }
|
|
52
|
+
model: { $resolver: model.plan }
|
|
53
|
+
builtins:
|
|
54
|
+
ask_user: true
|
|
55
|
+
submit_plan: required # blocks until approved
|
|
56
|
+
transitionsTo: execute
|
|
57
|
+
|
|
58
|
+
- id: execute
|
|
59
|
+
name: Execute
|
|
60
|
+
agent: { $resolver: my-agent }
|
|
61
|
+
model: { $resolver: model.execute }
|
|
62
|
+
builtins:
|
|
63
|
+
ask_user: false
|
|
64
|
+
subagent: true
|
|
65
|
+
|
|
66
|
+
models:
|
|
67
|
+
resolver: { $resolver: model.resolver } # (modelId) => LanguageModel
|
|
68
|
+
|
|
69
|
+
subagents:
|
|
70
|
+
- id: researcher
|
|
71
|
+
name: Researcher
|
|
72
|
+
description: Searches and summarises.
|
|
73
|
+
agent: { $resolver: researcher-agent }
|
|
74
|
+
forked: false # isolated thread (default)
|
|
75
|
+
maxSteps: 20
|
|
76
|
+
|
|
77
|
+
memory:
|
|
78
|
+
$resolver: mastra.memory.thread
|
|
79
|
+
|
|
80
|
+
observability:
|
|
81
|
+
$resolver: my.telemetry.entrypoint
|
|
82
|
+
---
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Required fields
|
|
86
|
+
|
|
87
|
+
| Field | Type | Notes |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `spec` | `"harness/v1"` | Version pin. |
|
|
90
|
+
| `id` | `string` (kebab-case) | Registry key; must be unique within a workspace. |
|
|
91
|
+
| `name` | `string` | Human label (≤ 80 chars). |
|
|
92
|
+
| `version` | `semver` | Bump on breaking mode / subagent changes. |
|
|
93
|
+
| `storage` | `refOrString` | Must resolve to `MastraCompositeStore`. |
|
|
94
|
+
| `modes` | `mode[]` | At least one mode required. |
|
|
95
|
+
| `models.resolver` | `refOrString` | `(modelId: string) => LanguageModel`. |
|
|
96
|
+
|
|
97
|
+
## Resolver syntax (`refOrString`)
|
|
98
|
+
|
|
99
|
+
Three forms are accepted for any field annotated `$ref: "#/$defs/refOrString"`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
# 1. Inline literal string (if the field accepts a raw value)
|
|
103
|
+
storage: "fs://./data/state"
|
|
104
|
+
|
|
105
|
+
# 2. Named registry ref — resolved at harness boot from the resolver registry
|
|
106
|
+
storage:
|
|
107
|
+
$ref: myApp.storage.main
|
|
108
|
+
|
|
109
|
+
# 3. Dynamic resolver call — arbitrary typed input passed to the resolver
|
|
110
|
+
storage:
|
|
111
|
+
$resolver: myApp.storage.build
|
|
112
|
+
input: { path: "./state", ttl: 3600 }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Modes
|
|
116
|
+
|
|
117
|
+
Each mode entry defines **one operational context**:
|
|
118
|
+
|
|
119
|
+
| Field | Required | Notes |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `id` | ✅ | Unique within this harness (kebab-case recommended). |
|
|
122
|
+
| `agent` | ✅ | Backing `Mastra Agent` instance (via resolver). |
|
|
123
|
+
| `model` | ✅ | Resolver returning `{ modelId, defaultModelId?, allowed? }`. |
|
|
124
|
+
| `default` | — | First mode with `default: true` activates on new sessions. |
|
|
125
|
+
| `transitionsTo` | — | Auto-switch to this mode id after `submit_plan` approval. |
|
|
126
|
+
| `tools` | — | Replaces the agent's built-in tools entirely (mutually exclusive with `additionalTools`). |
|
|
127
|
+
| `prompt.blocks` | — | Instruction blocks resolved and concatenated as `instructions`. |
|
|
128
|
+
| `builtins.*` | — | Enable / disable built-in tools: `ask_user`, `submit_plan`, `task_write`, `task_check`, `subagent`. |
|
|
129
|
+
| `permissions` | — | `PermissionRules` resolver — default tool-approval policy for this mode. |
|
|
130
|
+
|
|
131
|
+
### `submit_plan` values
|
|
132
|
+
|
|
133
|
+
| Value | Behaviour |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `false` (default) | Tool not registered. |
|
|
136
|
+
| `true` | Registered; plan approval is optional. |
|
|
137
|
+
| `"required"` | Registered; the mode blocks on plan approval and then transitions to `transitionsTo`. |
|
|
138
|
+
|
|
139
|
+
## Subagents
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
subagents:
|
|
143
|
+
- id: drafter
|
|
144
|
+
name: Drafter
|
|
145
|
+
description: Writes first-draft content.
|
|
146
|
+
agent: { $resolver: drafter-agent }
|
|
147
|
+
forked: true # inherits parent thread + prompt cache
|
|
148
|
+
maxSteps: 30
|
|
149
|
+
allowedHarnessTools: [ask_user, task_write]
|
|
150
|
+
allowedWorkspaceTools: [read_file, write_file]
|
|
151
|
+
prompt:
|
|
152
|
+
blocks:
|
|
153
|
+
- "You are a concise technical writer."
|
|
154
|
+
- { $ref: brand.voice.guide }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- `forked: true` — subagent inherits the parent conversation thread and prompt cache
|
|
158
|
+
(cheaper, shares context).
|
|
159
|
+
- `forked: false` (default) — fresh isolated thread; the subagent is context-blind to
|
|
160
|
+
the parent.
|
|
161
|
+
|
|
162
|
+
## Heartbeats
|
|
163
|
+
|
|
164
|
+
Heartbeats are periodic background handlers registered on the Harness constructor's
|
|
165
|
+
`heartbeats` array. Each entry is a `refOrString` resolving to a `HeartbeatConfig`
|
|
166
|
+
(interval + handler function). Common uses: Observational Memory reflector, progress
|
|
167
|
+
reporter, stale-session reaper.
|
|
168
|
+
|
|
169
|
+
## Loading algorithm
|
|
170
|
+
|
|
171
|
+
1. Locate `.harness/<slug>.md` in the workspace (or agent pack).
|
|
172
|
+
2. Parse the YAML frontmatter block; validate against `HARNESS.schema.json`.
|
|
173
|
+
3. Resolve all `$ref` / `$resolver` entries against the resolver registry at boot time
|
|
174
|
+
— fail loudly if any resolver is missing.
|
|
175
|
+
4. Instantiate the `Harness` object (Mastra constructor) with the resolved config.
|
|
176
|
+
5. Register in the harness registry keyed by `id`.
|
|
177
|
+
|
|
178
|
+
**Never execute a harness at load time** — only parse, validate, and register.
|
|
179
|
+
|
|
180
|
+
## Relationship to other AIPs
|
|
181
|
+
|
|
182
|
+
| AIP | Relationship |
|
|
183
|
+
|---|---|
|
|
184
|
+
| AIP-42 (Agent) | Harness agents are AIP-42 instances. A Harness orchestrates them; it is NOT an AIP-42 agent itself. |
|
|
185
|
+
| AIP-12 (Playbook) | Agent packs can auto-generate `.harness/` manifests from `modes/*.md` files during ingestion. |
|
|
186
|
+
| AIP-35 (Storage) | `storage` field resolves to a provider defined under AIP-35. |
|
|
187
|
+
| AIP-37 (Lifecycle Events) | Harness emits `harness-session-start`, `harness-mode-switch`, `harness-session-end` events. |
|
|
188
|
+
| AIP-47 (Role) | `permissions` per mode align with AIP-47 role-based access scopes. |
|
|
189
|
+
|
|
190
|
+
## See also
|
|
191
|
+
|
|
192
|
+
- `HARNESS.schema.json` — canonical validation schema
|
|
193
|
+
- `@mastra/core/harness` — canonical runtime implementation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/corpus-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "@agentproto/corpus-cli — the `corpus` binary. Validate, lint, and operate an AIP-10 corpus workspace from the command line. Local-topology host for @agentproto/corpus — pair with a local backing engine (qdrant docker / gbrain) for a fully offline corpus runtime.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"gray-matter": "^4.0.3",
|
|
53
53
|
"zod": "^4.4.3",
|
|
54
54
|
"@agentproto/cli-exec": "0.1.0-alpha.1",
|
|
55
|
-
"@agentproto/corpus": "0.1.
|
|
56
|
-
"@agentproto/corpus-presets": "0.1.
|
|
55
|
+
"@agentproto/corpus": "0.1.1",
|
|
56
|
+
"@agentproto/corpus-presets": "0.1.1"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node": "^25.6.2",
|