@staix/agent-hub 0.23.1 → 0.25.0
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.
- package/CHANGELOG.md +24 -0
- package/README.md +32 -5
- package/docs/agent-notes/adapters.md +5 -2
- package/docs/agent-notes/bus.md +1 -0
- package/docs/agent-notes/daemon.md +16 -2
- package/docs/agent-notes/tasks.md +9 -2
- package/docs/agent-notes/tests.md +3 -0
- package/docs/dogfood.md +16 -2
- package/docs/memory.md +1 -1
- package/docs/operations.md +198 -5
- package/docs/profiles.md +2 -0
- package/docs/quickstart.md +19 -4
- package/docs/security.md +225 -8
- package/docs/specs/2026-09-19-agent-hub-design.md +54 -1
- package/docs/specs/2026-09-19-multi-project-design.md +12 -1
- package/docs/specs/2026-11-01-research-campaigns-design.md +351 -0
- package/docs/verification/2026-10-31-0.24.0.md +63 -0
- package/docs/verification/2026-10-31-claude-implementer-2.1.316.md +65 -0
- package/docs/verification/2026-11-01-0.25.0.md +91 -0
- package/docs/verification/claude-shell-wrapper-native.py +1 -1
- package/docs/verified.json +31 -15
- package/package.json +4 -3
- package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
- package/plugins/agent-hub/server.js +5120 -4710
- package/src/adapters/claude-channel.ts +29 -6
- package/src/adapters/compat.ts +3 -3
- package/src/adapters/definitions/native-cli-claude-setup.ts +4 -0
- package/src/adapters/definitions/native-cli-doctor.ts +30 -0
- package/src/adapters/jcode.ts +3 -0
- package/src/adapters/registry.ts +1 -1
- package/src/cli/acon-register.ts +29 -0
- package/src/cli/autonomy-homes.ts +33 -0
- package/src/cli/autonomy-offline.ts +75 -0
- package/src/cli/autonomy-projects.ts +103 -0
- package/src/cli/autonomy.ts +44 -0
- package/src/cli/claude-homes.ts +123 -0
- package/src/cli/claude-profile-hook.ts +130 -0
- package/src/cli/handoff-args.ts +27 -0
- package/src/cli/handoff-output.ts +25 -0
- package/src/cli/help.ts +8 -4
- package/src/cli/identity.ts +8 -1
- package/src/cli/main.ts +174 -33
- package/src/cli/output.ts +8 -5
- package/src/cli/schedule-output.ts +8 -4
- package/src/cli/setup-homes.ts +46 -0
- package/src/cli/setup.ts +1 -1
- package/src/cli/study-output.ts +71 -0
- package/src/cli/study.ts +58 -0
- package/src/cli/task-output.ts +1 -0
- package/src/hub/action-class.ts +203 -14
- package/src/hub/action-enforce.ts +8 -6
- package/src/hub/action-policy.ts +95 -9
- package/src/hub/autonomy-consent.ts +173 -0
- package/src/hub/autonomy-defaults.ts +58 -0
- package/src/hub/autonomy.ts +232 -0
- package/src/hub/board.ts +871 -2
- package/src/hub/channel-project.ts +61 -0
- package/src/hub/config-apply.ts +3 -2
- package/src/hub/confirmation-matrix.ts +202 -0
- package/src/hub/control-client.ts +10 -1
- package/src/hub/daemon.ts +546 -27
- package/src/hub/envelope.ts +2 -0
- package/src/hub/events.ts +4 -1
- package/src/hub/execution-budget.ts +12 -0
- package/src/hub/handoff.ts +126 -0
- package/src/hub/hub-tools.ts +12 -2
- package/src/hub/manager.ts +64 -57
- package/src/hub/no-writes.ts +1 -1
- package/src/hub/path-policy.ts +12 -8
- package/src/hub/project.ts +14 -5
- package/src/hub/provenance.ts +30 -0
- package/src/hub/research-campaign.ts +265 -0
- package/src/hub/research-experiments.ts +445 -0
- package/src/hub/restart.ts +26 -0
- package/src/hub/schedules.ts +210 -9
- package/src/hub/session-identity.ts +49 -0
- package/src/hub/settings.ts +105 -8
- package/src/hub/task-repository.ts +11 -6
- package/src/hub/tasks.ts +894 -22
- package/src/hub/ui.ts +15 -6
- package/src/memory/capture.ts +2 -2
- package/src/ui/index.html +5 -3
- package/src/ui/office-space.ts +118 -0
- package/src/ui/plugin.ts +293 -0
- package/templates/AGENTS.block.md +1 -0
- package/templates/presets/autonomous.json +161 -0
- package/templates/presets/confirmation-matrix.json +943 -0
- package/templates/profiles/general.json +1 -1
- package/templates/profiles/research.json +4 -4
- package/templates/profiles/writing.json +1 -1
- package/templates/roles/research/analyst.md +1 -0
- package/templates/roles/research/fact-checker.md +1 -0
- package/templates/roles/research/research-lead.md +1 -0
- package/templates/roles/research/researcher.md +1 -0
- package/templates/roles/research/statistician.md +1 -0
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"issue": "#999",
|
|
4
|
+
"phase": "T0",
|
|
5
|
+
"about": "Model-free inventory of every place a person is asked to confirm during a standard task (plan, implement, PR, review, merge), per agent kind and environment. It records what the code and docs say today and changes no behaviour. T1's templates/presets/autonomous.json and `ahub autonomy status` read it. A fact that could not be established is the word unknown, never a guess. Add a row for a new peer kind here (src/hub/confirmation-matrix.ts and test/confirmation-matrix.test.ts fail without one).",
|
|
6
|
+
"environments": {
|
|
7
|
+
"terminal": {
|
|
8
|
+
"detect": "No ORCA_WORKTREE_ID in the hub's environment and no Orca worktree on record for the project.",
|
|
9
|
+
"opens": "A hub-made TUI start needs the machine-local terminal.open template. With none the start is refused with the command to run by hand, never downgraded to headless."
|
|
10
|
+
},
|
|
11
|
+
"orca": {
|
|
12
|
+
"detect": "ORCA_WORKTREE_ID is set, or an earlier ahub <peer> launch of this project recorded an Orca worktree, and the orca executable is on PATH.",
|
|
13
|
+
"opens": "A hub-made TUI start runs `orca terminal create` in that worktree. A configured terminal.open template takes precedence."
|
|
14
|
+
},
|
|
15
|
+
"headless": {
|
|
16
|
+
"detect": "No terminal: peers started with start_mode headless, the hub-native local worker, or a declared headless instance.",
|
|
17
|
+
"opens": "Nothing opens for the peer. A headless Kimi or Qwen start also opens an `ahub watch` pane through the provider when one exists, and the start stands without it."
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"kinds": {
|
|
21
|
+
"claude": { "forms": ["tui"], "extraForms": ["headless"], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "mapped", "formNote": "The kind itself has only a TUI. headless is a declared headless implementer instance (the Claude headless implementer, #525-4)." },
|
|
22
|
+
"codex": { "forms": ["tui", "headless"], "extraForms": [], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "mapped" },
|
|
23
|
+
"kimi": { "forms": ["tui", "headless"], "extraForms": [], "conductorStartable": true, "pullOnlyForms": ["tui"], "hubMode": "unmanaged-in-tui" },
|
|
24
|
+
"qwen": { "forms": ["headless"], "extraForms": ["tui"], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "mapped", "formNote": "Headless ACP is the default. The TUI is explicit only (ahub qwen --mode tui, dual output) and the hub never opens it by itself." },
|
|
25
|
+
"jcode": { "forms": ["tui", "headless"], "extraForms": [], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "unmanaged" },
|
|
26
|
+
"pi": { "forms": ["tui", "headless"], "extraForms": [], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "mapped" },
|
|
27
|
+
"local": { "forms": ["headless"], "extraForms": [], "conductorStartable": true, "pullOnlyForms": [], "hubMode": "mapped" },
|
|
28
|
+
"agy": { "forms": ["tui"], "extraForms": [], "conductorStartable": false, "pullOnlyForms": ["tui"], "hubMode": "unmanaged" }
|
|
29
|
+
},
|
|
30
|
+
"keys": {
|
|
31
|
+
"permission_modes.<peer>": {
|
|
32
|
+
"kind": "setting",
|
|
33
|
+
"setting": "permission_modes.<peer>",
|
|
34
|
+
"appliesTo": ["claude", "codex", "kimi", "pi", "local", "qwen"],
|
|
35
|
+
"where": ".agenthub/config.local.json (a git-tracked value is ignored)",
|
|
36
|
+
"applies": "the peer's next start",
|
|
37
|
+
"default": "ask",
|
|
38
|
+
"setBy": "the person (a never-ask default also needs the console y at hub start)",
|
|
39
|
+
"doc": "docs/operations.md, Permission modes for running peers"
|
|
40
|
+
},
|
|
41
|
+
"permission.<peer>": {
|
|
42
|
+
"kind": "setting",
|
|
43
|
+
"setting": "permission.<peer>",
|
|
44
|
+
"appliesTo": ["claude", "codex", "kimi", "pi", "local", "qwen"],
|
|
45
|
+
"where": "the daemon's memory only (ahub permission <peer> <mode>, dashboard, ahub settings)",
|
|
46
|
+
"applies": "live, until the hub stops",
|
|
47
|
+
"default": "the permission_modes default, else ask",
|
|
48
|
+
"setBy": "the person (never-ask needs the peer id typed or --yes plus the console y)",
|
|
49
|
+
"doc": "docs/operations.md, Permission modes for running peers"
|
|
50
|
+
},
|
|
51
|
+
"action_policy": {
|
|
52
|
+
"kind": "file",
|
|
53
|
+
"setting": null,
|
|
54
|
+
"where": ".agenthub/config.local.json only (enabled, always_ask, budgets, floor). Shared config.json cannot set it.",
|
|
55
|
+
"applies": "live through the confirmed terminal reload",
|
|
56
|
+
"default": "enabled, always_ask is publish, external-write, destroy and install, budgets 1, 5, 3, 2, floor off. floor: true (#999 T3) lets a push of a non-default branch and gh pr create, comment, review and merge in the project's own repository run without a prompt, and leaves force push, the default branch, tags, gh release, package publish, deletion outside the root, other repositories, mail and posting asking",
|
|
57
|
+
"setBy": "the person (settings action_policy.enabled and action_policy.budgets.<class> are registered)",
|
|
58
|
+
"doc": "docs/operations.md, Always-ask action policy foundation"
|
|
59
|
+
},
|
|
60
|
+
"tasks.auto_pull": {
|
|
61
|
+
"kind": "setting",
|
|
62
|
+
"setting": "tasks.auto_pull",
|
|
63
|
+
"where": ".agenthub/config.local.json (machine-local, a committed value is ignored)",
|
|
64
|
+
"applies": "live",
|
|
65
|
+
"default": "false",
|
|
66
|
+
"setBy": "the person (risk raises)",
|
|
67
|
+
"doc": "docs/operations.md, Settings from the dashboard and the terminal"
|
|
68
|
+
},
|
|
69
|
+
"task_sweep.enabled": {
|
|
70
|
+
"kind": "setting",
|
|
71
|
+
"setting": "task_sweep.enabled",
|
|
72
|
+
"where": ".agenthub/config.json or config.local.json",
|
|
73
|
+
"applies": "live",
|
|
74
|
+
"default": "false",
|
|
75
|
+
"setBy": "the person (risk raises)",
|
|
76
|
+
"doc": "docs/operations.md, Task idle sweep"
|
|
77
|
+
},
|
|
78
|
+
"task_sweep.auto_reassign": {
|
|
79
|
+
"kind": "setting",
|
|
80
|
+
"setting": "task_sweep.auto_reassign",
|
|
81
|
+
"where": ".agenthub/config.json or config.local.json",
|
|
82
|
+
"applies": "live",
|
|
83
|
+
"default": "false",
|
|
84
|
+
"setBy": "the person (risk raises)",
|
|
85
|
+
"doc": "docs/operations.md, Task idle sweep"
|
|
86
|
+
},
|
|
87
|
+
"peers.<peer>.start_mode": {
|
|
88
|
+
"kind": "setting",
|
|
89
|
+
"setting": "peers.<peer>.start_mode",
|
|
90
|
+
"appliesTo": ["codex", "kimi", "pi", "jcode"],
|
|
91
|
+
"where": ".agenthub/config.local.json",
|
|
92
|
+
"applies": "the peer's next start",
|
|
93
|
+
"default": "tui",
|
|
94
|
+
"setBy": "the person",
|
|
95
|
+
"doc": "docs/operations.md, Start modes: TUI by default, headless as opt-in"
|
|
96
|
+
},
|
|
97
|
+
"terminal.open": {
|
|
98
|
+
"kind": "file",
|
|
99
|
+
"setting": null,
|
|
100
|
+
"where": ".agenthub/config.local.json (an argv template with one {command} element). Not a setting: read at hub start.",
|
|
101
|
+
"applies": "the next hub start",
|
|
102
|
+
"default": "none, so a hub-made TUI start uses Orca when it can, else is refused",
|
|
103
|
+
"setBy": "the person editing the file",
|
|
104
|
+
"doc": "docs/operations.md, Start modes: TUI by default, headless as opt-in"
|
|
105
|
+
},
|
|
106
|
+
"pi.auto_start": {
|
|
107
|
+
"kind": "setting",
|
|
108
|
+
"setting": "pi.auto_start",
|
|
109
|
+
"appliesTo": ["pi"],
|
|
110
|
+
"where": ".agenthub/config.local.json",
|
|
111
|
+
"applies": "the next startup or recovery auto-start decision",
|
|
112
|
+
"default": "false",
|
|
113
|
+
"setBy": "the person",
|
|
114
|
+
"doc": "docs/operations.md, Settings from the dashboard and the terminal"
|
|
115
|
+
},
|
|
116
|
+
"approvals.timeout_s": {
|
|
117
|
+
"kind": "file",
|
|
118
|
+
"setting": null,
|
|
119
|
+
"where": ".agenthub/config.json (30 to 3600 seconds)",
|
|
120
|
+
"applies": "the next hub start",
|
|
121
|
+
"default": "120",
|
|
122
|
+
"setBy": "the person editing the file",
|
|
123
|
+
"doc": "docs/operations.md, Approvals and pauses"
|
|
124
|
+
},
|
|
125
|
+
"launch.unattended": {
|
|
126
|
+
"kind": "launch-flag",
|
|
127
|
+
"setting": null,
|
|
128
|
+
"where": "ahub up|daemon --unattended (hub level), ahub claude --unattended, ahub codex --unattended",
|
|
129
|
+
"applies": "that launch",
|
|
130
|
+
"default": "off",
|
|
131
|
+
"setBy": "the person typing the launch command",
|
|
132
|
+
"doc": "docs/security.md"
|
|
133
|
+
},
|
|
134
|
+
"sdlc.auto_merge": {
|
|
135
|
+
"kind": "file",
|
|
136
|
+
"setting": null,
|
|
137
|
+
"where": ".agenthub/sdlc.toml (top level or [repos.\"owner/name\"])",
|
|
138
|
+
"applies": "read once at hub start",
|
|
139
|
+
"default": "off",
|
|
140
|
+
"setBy": "the person editing the file",
|
|
141
|
+
"doc": "docs/sdlc.md, Guarded merge"
|
|
142
|
+
},
|
|
143
|
+
"release.authorize": {
|
|
144
|
+
"kind": "command",
|
|
145
|
+
"setting": null,
|
|
146
|
+
"where": "ahub sdlc authorize-release <version> in a person's terminal, plus the managed pre-push tag guard",
|
|
147
|
+
"applies": "per release, held in daemon memory only",
|
|
148
|
+
"default": "no authorization",
|
|
149
|
+
"setBy": "the person alone (agents and delegated calls cannot)",
|
|
150
|
+
"doc": "docs/operations.md, Release approval and optional tag guard"
|
|
151
|
+
},
|
|
152
|
+
"native.claude": {
|
|
153
|
+
"kind": "native",
|
|
154
|
+
"setting": null,
|
|
155
|
+
"appliesTo": ["claude"],
|
|
156
|
+
"where": "Claude Code's own permission rules and settings, under ~/.claude or the CLAUDE_CONFIG_DIR home in use",
|
|
157
|
+
"applies": "native",
|
|
158
|
+
"default": "Claude's own policy",
|
|
159
|
+
"setBy": "the person, outside the hub",
|
|
160
|
+
"doc": "docs/operations.md, Permission modes for running peers"
|
|
161
|
+
},
|
|
162
|
+
"native.codex": {
|
|
163
|
+
"kind": "native",
|
|
164
|
+
"setting": null,
|
|
165
|
+
"appliesTo": ["codex"],
|
|
166
|
+
"where": "Codex's own approval policy and sandbox, under CODEX_HOME",
|
|
167
|
+
"applies": "native",
|
|
168
|
+
"default": "Codex's own policy",
|
|
169
|
+
"setBy": "the person, outside the hub",
|
|
170
|
+
"doc": "docs/agent-notes/adapters.md, Permissions, modes and approvals"
|
|
171
|
+
},
|
|
172
|
+
"native.kimi": {
|
|
173
|
+
"kind": "native",
|
|
174
|
+
"setting": null,
|
|
175
|
+
"appliesTo": ["kimi"],
|
|
176
|
+
"where": "Kimi's own TUI permission mode. The hub sets ACP default, yolo or auto only for its headless session.",
|
|
177
|
+
"applies": "native",
|
|
178
|
+
"default": "Kimi's own policy",
|
|
179
|
+
"setBy": "the person, in Kimi's TUI",
|
|
180
|
+
"doc": "docs/operations.md, Kimi in its own TUI"
|
|
181
|
+
},
|
|
182
|
+
"native.qwen": {
|
|
183
|
+
"kind": "native",
|
|
184
|
+
"setting": null,
|
|
185
|
+
"appliesTo": ["qwen"],
|
|
186
|
+
"where": "Qwen's own approval mode. The dual-output TUI is launched with --approval-mode default.",
|
|
187
|
+
"applies": "native",
|
|
188
|
+
"default": "Qwen's own policy",
|
|
189
|
+
"setBy": "the person, outside the hub",
|
|
190
|
+
"doc": "docs/operations.md, Qwen's own TUI, driven through dual output"
|
|
191
|
+
},
|
|
192
|
+
"native.jcode": {
|
|
193
|
+
"kind": "native",
|
|
194
|
+
"setting": null,
|
|
195
|
+
"appliesTo": ["jcode"],
|
|
196
|
+
"where": "Jcode's native policy. permission_modes.jcode is refused by the config loader.",
|
|
197
|
+
"applies": "native",
|
|
198
|
+
"default": "Jcode's own policy",
|
|
199
|
+
"setBy": "the person, outside the hub",
|
|
200
|
+
"doc": "docs/operations.md, Optional Jcode peer"
|
|
201
|
+
},
|
|
202
|
+
"native.agy": {
|
|
203
|
+
"kind": "native",
|
|
204
|
+
"setting": null,
|
|
205
|
+
"appliesTo": ["agy"],
|
|
206
|
+
"where": "Antigravity's own TUI permission mode. --dangerously-skip-permissions and --unattended are refused by ahub agy.",
|
|
207
|
+
"applies": "native",
|
|
208
|
+
"default": "Antigravity's own policy",
|
|
209
|
+
"setBy": "the person, in Antigravity's TUI",
|
|
210
|
+
"doc": "docs/operations.md, Optional Antigravity (agy) peer"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"unavailable": [
|
|
214
|
+
{ "kind": "agy", "environment": "headless", "reason": "Antigravity has no headless form. Headless and print starts are refused until their native mapping is verified." }
|
|
215
|
+
],
|
|
216
|
+
"rows": [
|
|
217
|
+
{
|
|
218
|
+
"id": "claude.tool-approval.tui",
|
|
219
|
+
"kinds": ["claude"],
|
|
220
|
+
"environments": ["terminal", "orca"],
|
|
221
|
+
"form": "tui",
|
|
222
|
+
"point": "tool-approval",
|
|
223
|
+
"asks": "Claude's own permission dialog for a write, edit, shell or other tool call in the person's terminal.",
|
|
224
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "native.claude", "launch.unattended"],
|
|
225
|
+
"hubSeesBeforeRun": "yes",
|
|
226
|
+
"askedBy": "native-tui",
|
|
227
|
+
"note": "In a managed launch (ahub claude) the PreToolUse hook sees every call. ask gives no hook decision, so Claude's own rules ask. ask-when-needed lets project file tools run outside .agenthub, .git and agent configuration. never-ask returns a hook allow for every tool. A session not started by ahub claude has no hub hook, and an --unattended launch skips every permission check, hooks included: the hub sees nothing there.",
|
|
228
|
+
"evidence": [
|
|
229
|
+
{ "file": "docs/operations.md", "needle": "Hook allow for every tool" },
|
|
230
|
+
{ "file": "src/adapters/definitions/builtin-metadata.ts", "needle": "Claude's own permission rules decide" }
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"id": "claude.classed-action.tui",
|
|
235
|
+
"kinds": ["claude"],
|
|
236
|
+
"environments": ["terminal", "orca"],
|
|
237
|
+
"form": "tui",
|
|
238
|
+
"point": "classed-action",
|
|
239
|
+
"asks": "Claude's permission dialog for a publish, external-write, destroy or install call, returned as ask by the hub hook.",
|
|
240
|
+
"controlledBy": ["action_policy", "launch.unattended"],
|
|
241
|
+
"hubSeesBeforeRun": "yes",
|
|
242
|
+
"askedBy": "native-tui",
|
|
243
|
+
"note": "The hook returns ask in ask, ask-when-needed and never-ask alike, and ask beats every allow the hook would add. Claude's dialog cannot carry a class budget, so every classed call asks. Not enforced without a hub hook or under --unattended.",
|
|
244
|
+
"evidence": [
|
|
245
|
+
{ "file": "docs/operations.md", "needle": "Always-ask action policy foundation" },
|
|
246
|
+
{ "file": "src/hub/daemon.ts", "needle": "this Claude launch is --unattended" }
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"id": "claude.hub-tools.tui",
|
|
251
|
+
"kinds": ["claude"],
|
|
252
|
+
"environments": ["terminal", "orca"],
|
|
253
|
+
"form": "tui",
|
|
254
|
+
"point": "hub-tools",
|
|
255
|
+
"asks": "Whether Claude asks before calling the plugin's hub_* MCP tools.",
|
|
256
|
+
"controlledBy": ["permission.<peer>", "native.claude"],
|
|
257
|
+
"hubSeesBeforeRun": "unknown",
|
|
258
|
+
"askedBy": "unknown",
|
|
259
|
+
"note": "unknown: no allow rule for the hub tools was found in the plugin or the launcher. In ask and ask-when-needed Claude's own rules decide. never-ask returns a hook allow for every tool.",
|
|
260
|
+
"unknowns": ["whether Claude asks before calling the hub's hub_* tools in ask and ask-when-needed"],
|
|
261
|
+
"evidence": [
|
|
262
|
+
{ "file": "docs/operations.md", "needle": "Hook allow for every tool" }
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"id": "claude.channel-confirmation.tui",
|
|
267
|
+
"kinds": ["claude"],
|
|
268
|
+
"environments": ["terminal", "orca"],
|
|
269
|
+
"form": "tui",
|
|
270
|
+
"point": "session-start",
|
|
271
|
+
"asks": "Claude's native development-channel confirmation for the hub channel (--dangerously-load-development-channels).",
|
|
272
|
+
"controlledBy": ["native.claude"],
|
|
273
|
+
"hubSeesBeforeRun": "no",
|
|
274
|
+
"askedBy": "native-tui",
|
|
275
|
+
"note": "Recorded as an attended step when a recovery recreates a Claude session. unknown: whether it appears on every ordinary ahub claude start, and whether Orca profile homes differ.",
|
|
276
|
+
"unknowns": ["whether the confirmation appears on every ordinary ahub claude start", "whether Orca profile homes differ"],
|
|
277
|
+
"evidence": [
|
|
278
|
+
{ "file": "docs/smoke.md", "needle": "development-channel confirmation" },
|
|
279
|
+
{ "file": "src/adapters/definitions/builtin-metadata.ts", "needle": "--dangerously-load-development-channels" }
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"id": "claude.tool-approval.headless",
|
|
284
|
+
"kinds": ["claude"],
|
|
285
|
+
"environments": ["headless"],
|
|
286
|
+
"form": "headless",
|
|
287
|
+
"point": "tool-approval",
|
|
288
|
+
"asks": "The person's allow-once through the hub's permission prompt tool, on the console, for a write or shell call of a declared headless implementer.",
|
|
289
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "approvals.timeout_s"],
|
|
290
|
+
"hubSeesBeforeRun": "yes",
|
|
291
|
+
"askedBy": "hub-console",
|
|
292
|
+
"note": "ask asks for every write and shell call. ask-when-needed lets safe project file tools, proven read-only shell commands and bound task commands inside the owned worktree run. There is no never-ask or acceptEdits bypass: never-ask and --unattended are refused at startup. No answer is a denial after approvals.timeout_s. Only a declared headless implementer instance has this form.",
|
|
293
|
+
"evidence": [
|
|
294
|
+
{ "file": "docs/operations.md", "needle": "There is no `acceptEdits` or `never-ask` bypass" },
|
|
295
|
+
{ "file": "src/adapters/claude-implementer.ts", "needle": "hub_permission_request" }
|
|
296
|
+
]
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"id": "claude.classed-action.headless",
|
|
300
|
+
"kinds": ["claude"],
|
|
301
|
+
"environments": ["headless"],
|
|
302
|
+
"form": "headless",
|
|
303
|
+
"point": "classed-action",
|
|
304
|
+
"asks": "The person's allow-once or denial for a publish, external-write, destroy or install call of the headless implementer.",
|
|
305
|
+
"controlledBy": ["action_policy", "approvals.timeout_s"],
|
|
306
|
+
"hubSeesBeforeRun": "yes",
|
|
307
|
+
"askedBy": "hub-console",
|
|
308
|
+
"note": "The managed hook asks and the current-child-bound prompt tool accepts only a person's allow-once or denial. Not enforced while there is no current managed child.",
|
|
309
|
+
"evidence": [
|
|
310
|
+
{ "file": "docs/operations.md", "needle": "Claude headless implementer" },
|
|
311
|
+
{ "file": "src/hub/daemon.ts", "needle": "no current managed Claude implementer child" }
|
|
312
|
+
]
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"id": "claude.hub-tools.headless",
|
|
316
|
+
"kinds": ["claude"],
|
|
317
|
+
"environments": ["headless"],
|
|
318
|
+
"form": "headless",
|
|
319
|
+
"point": "hub-tools",
|
|
320
|
+
"asks": "None: the implementer's hub tools are an explicit allowed-tools list.",
|
|
321
|
+
"controlledBy": [],
|
|
322
|
+
"hubSeesBeforeRun": "yes",
|
|
323
|
+
"askedBy": "none",
|
|
324
|
+
"evidence": [
|
|
325
|
+
{ "file": "src/adapters/claude-implementer.ts", "needle": "IMPLEMENTER_HUB_TOOL_NAMES" }
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"id": "codex.tool-approval.tui",
|
|
330
|
+
"kinds": ["codex"],
|
|
331
|
+
"environments": ["terminal", "orca"],
|
|
332
|
+
"form": "tui",
|
|
333
|
+
"point": "tool-approval",
|
|
334
|
+
"asks": "Codex's approval prompts in its TUI for commands, file changes and permission profiles.",
|
|
335
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "native.codex", "launch.unattended"],
|
|
336
|
+
"hubSeesBeforeRun": "partial",
|
|
337
|
+
"askedBy": "native-tui",
|
|
338
|
+
"note": "ask-when-needed sends approval policy on-request on every turn, never-ask sends never so nothing asks, and ask restores the captured native policy once. Received command approval requests are classed by the hub before they reach the TUI. File-change, writeStdin, permission-profile and unreadable requests keep native handling, and native policy can run a call without sending a request. --unattended passes --dangerously-bypass-approvals-and-sandbox and is refused under a non-ask mode.",
|
|
339
|
+
"evidence": [
|
|
340
|
+
{ "file": "docs/operations.md", "needle": "on-request for every outgoing turn/start" },
|
|
341
|
+
{ "file": "src/adapters/codex-appserver.ts", "needle": "interceptActionApproval" }
|
|
342
|
+
]
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"id": "codex.classed-action.tui",
|
|
346
|
+
"kinds": ["codex"],
|
|
347
|
+
"environments": ["terminal", "orca"],
|
|
348
|
+
"form": "tui",
|
|
349
|
+
"point": "classed-action",
|
|
350
|
+
"asks": "The hub console's allow-once or deny, with an optional class budget, for a classed command approval request.",
|
|
351
|
+
"controlledBy": ["action_policy", "permission.<peer>"],
|
|
352
|
+
"hubSeesBeforeRun": "partial",
|
|
353
|
+
"askedBy": "hub-console",
|
|
354
|
+
"note": "The status row says not enforceable: native policy can execute without emitting an approval request, and never-ask sends approvalPolicy never.",
|
|
355
|
+
"evidence": [
|
|
356
|
+
{ "file": "src/hub/daemon.ts", "needle": "native policy can execute without sending one" }
|
|
357
|
+
]
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"id": "codex.tool-approval.headless",
|
|
361
|
+
"kinds": ["codex"],
|
|
362
|
+
"environments": ["headless"],
|
|
363
|
+
"form": "headless",
|
|
364
|
+
"point": "tool-approval",
|
|
365
|
+
"asks": "Approval requests of the hub-started Codex app-server, answered by whatever is attached to it.",
|
|
366
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "peers.<peer>.start_mode", "native.codex"],
|
|
367
|
+
"hubSeesBeforeRun": "unknown",
|
|
368
|
+
"askedBy": "unknown",
|
|
369
|
+
"note": "unknown: with peers.codex.start_mode headless there is no TUI, and the code gates a classed command request only while a TUI link is open. The mode override (on-request or never) applies to every hub turn/start.",
|
|
370
|
+
"unknowns": ["who answers a Codex approval request when no TUI is attached", "whether the hub gates a classed request with no TUI link"],
|
|
371
|
+
"evidence": [
|
|
372
|
+
{ "file": "docs/operations.md", "needle": "a hub-made start runs the app-server only" },
|
|
373
|
+
{ "file": "src/adapters/codex-appserver.ts", "needle": "applyPermissionPolicy" }
|
|
374
|
+
]
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"id": "codex.classed-action.headless",
|
|
378
|
+
"kinds": ["codex"],
|
|
379
|
+
"environments": ["headless"],
|
|
380
|
+
"form": "headless",
|
|
381
|
+
"point": "classed-action",
|
|
382
|
+
"asks": "The hub console's allow-once or deny for a classed command approval request, when one is sent.",
|
|
383
|
+
"controlledBy": ["action_policy", "permission.<peer>"],
|
|
384
|
+
"hubSeesBeforeRun": "unknown",
|
|
385
|
+
"askedBy": "unknown",
|
|
386
|
+
"note": "unknown: see codex.tool-approval.headless. Never-ask sends no request at all.",
|
|
387
|
+
"unknowns": ["who answers a classed Codex request when no TUI is attached"],
|
|
388
|
+
"evidence": [
|
|
389
|
+
{ "file": "src/adapters/codex-appserver.ts", "needle": "interceptActionApproval" }
|
|
390
|
+
]
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"id": "kimi.tool-approval.tui",
|
|
394
|
+
"kinds": ["kimi"],
|
|
395
|
+
"environments": ["terminal", "orca"],
|
|
396
|
+
"form": "tui",
|
|
397
|
+
"point": "tool-approval",
|
|
398
|
+
"asks": "Kimi's own TUI permission prompts.",
|
|
399
|
+
"controlledBy": ["native.kimi"],
|
|
400
|
+
"hubSeesBeforeRun": "no",
|
|
401
|
+
"askedBy": "native-tui",
|
|
402
|
+
"note": "Pull-only: no hub permission mode, busy state, watchdog or console approval. The status row says Kimi approves tools in its own TUI.",
|
|
403
|
+
"evidence": [
|
|
404
|
+
{ "file": "src/adapters/definitions/builtin-metadata.ts", "needle": "Kimi approves tools and selects its permission mode in its own TUI" }
|
|
405
|
+
]
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"id": "kimi.classed-action.tui",
|
|
409
|
+
"kinds": ["kimi"],
|
|
410
|
+
"environments": ["terminal", "orca"],
|
|
411
|
+
"form": "tui",
|
|
412
|
+
"point": "classed-action",
|
|
413
|
+
"asks": "Whatever Kimi's own TUI asks. The hub classifies nothing in this form.",
|
|
414
|
+
"controlledBy": ["native.kimi"],
|
|
415
|
+
"hubSeesBeforeRun": "no",
|
|
416
|
+
"askedBy": "native-tui",
|
|
417
|
+
"evidence": [
|
|
418
|
+
{ "file": "docs/operations.md", "needle": "The TUI is pull-only." }
|
|
419
|
+
]
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"id": "kimi.hub-tools.tui",
|
|
423
|
+
"kinds": ["kimi"],
|
|
424
|
+
"environments": ["terminal", "orca"],
|
|
425
|
+
"form": "tui",
|
|
426
|
+
"point": "hub-tools",
|
|
427
|
+
"asks": "Whether Kimi's TUI asks before calling hub_* tools through its project MCP entry.",
|
|
428
|
+
"controlledBy": ["native.kimi"],
|
|
429
|
+
"hubSeesBeforeRun": "unknown",
|
|
430
|
+
"askedBy": "unknown",
|
|
431
|
+
"note": "unknown: the TUI's own prompts are not observable by the hub.",
|
|
432
|
+
"unknowns": ["whether Kimi's TUI asks before calling hub tools"],
|
|
433
|
+
"evidence": [
|
|
434
|
+
{ "file": "docs/operations.md", "needle": "Kimi in its own TUI" }
|
|
435
|
+
]
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
"id": "kimi.tool-approval.headless",
|
|
439
|
+
"kinds": ["kimi"],
|
|
440
|
+
"environments": ["headless"],
|
|
441
|
+
"form": "headless",
|
|
442
|
+
"point": "tool-approval",
|
|
443
|
+
"asks": "ACP session/request_permission, answered on the hub console (ahub permit or the dashboard).",
|
|
444
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "peers.<peer>.start_mode", "approvals.timeout_s", "launch.unattended"],
|
|
445
|
+
"hubSeesBeforeRun": "partial",
|
|
446
|
+
"askedBy": "hub-console",
|
|
447
|
+
"note": "ask maps to Kimi default, ask-when-needed to yolo and never-ask to auto. In yolo and auto Kimi sends no request for a call that mode allows, so the hub does not see it. An unanswered request is cancelled as a denial after approvals.timeout_s. ahub up --unattended answers unclassed requests allow-once on its own.",
|
|
448
|
+
"evidence": [
|
|
449
|
+
{ "file": "docs/operations.md", "needle": "ACP yolo" },
|
|
450
|
+
{ "file": "src/hub/daemon.ts", "needle": "its native mode ${mode} sends no request for a call it allows" }
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"id": "kimi.classed-action.headless",
|
|
455
|
+
"kinds": ["kimi"],
|
|
456
|
+
"environments": ["headless"],
|
|
457
|
+
"form": "headless",
|
|
458
|
+
"point": "classed-action",
|
|
459
|
+
"asks": "A console prompt titled Action approval with the classes, never auto-approved and without allow_always.",
|
|
460
|
+
"controlledBy": ["action_policy", "permission.<peer>", "approvals.timeout_s"],
|
|
461
|
+
"hubSeesBeforeRun": "partial",
|
|
462
|
+
"askedBy": "hub-console",
|
|
463
|
+
"note": "Enforced only while the peer's native mode is ask. A request whose payload the agent did not report is not classed. Under --unattended a classed request still waits for a person.",
|
|
464
|
+
"evidence": [
|
|
465
|
+
{ "file": "docs/operations.md", "needle": "Action approval (<classes>): <command>" }
|
|
466
|
+
]
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
"id": "kimi.hub-tools.headless",
|
|
470
|
+
"kinds": ["kimi"],
|
|
471
|
+
"environments": ["headless"],
|
|
472
|
+
"form": "headless",
|
|
473
|
+
"point": "hub-tools",
|
|
474
|
+
"asks": "None for the hub's own tools: an exact mcp__agent-hub__<name> title is auto-approved with allow-once only.",
|
|
475
|
+
"controlledBy": [],
|
|
476
|
+
"hubSeesBeforeRun": "yes",
|
|
477
|
+
"askedBy": "none",
|
|
478
|
+
"evidence": [
|
|
479
|
+
{ "file": "src/hub/daemon.ts", "needle": "HUB_TOOL_TITLES" }
|
|
480
|
+
]
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"id": "qwen.tool-approval.headless",
|
|
484
|
+
"kinds": ["qwen"],
|
|
485
|
+
"environments": ["terminal", "orca", "headless"],
|
|
486
|
+
"form": "headless",
|
|
487
|
+
"point": "tool-approval",
|
|
488
|
+
"asks": "ACP permission requests of the headless Qwen, answered on the hub console.",
|
|
489
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "approvals.timeout_s", "launch.unattended"],
|
|
490
|
+
"hubSeesBeforeRun": "partial",
|
|
491
|
+
"askedBy": "hub-console",
|
|
492
|
+
"note": "ask maps to default, ask-when-needed to auto-edit (file edits run, shell commands ask) and never-ask to yolo, which approves every tool outside any hub sandbox. Qwen is not a start-mode peer: a hub start is headless in every environment, plus a watch pane where a provider exists.",
|
|
493
|
+
"evidence": [
|
|
494
|
+
{ "file": "docs/operations.md", "needle": "Modes: ask maps to default, scoped frequency maps to auto-edit" }
|
|
495
|
+
]
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
"id": "qwen.classed-action.headless",
|
|
499
|
+
"kinds": ["qwen"],
|
|
500
|
+
"environments": ["terminal", "orca", "headless"],
|
|
501
|
+
"form": "headless",
|
|
502
|
+
"point": "classed-action",
|
|
503
|
+
"asks": "A console prompt titled Action approval with the classes, never auto-approved.",
|
|
504
|
+
"controlledBy": ["action_policy", "permission.<peer>", "approvals.timeout_s"],
|
|
505
|
+
"hubSeesBeforeRun": "partial",
|
|
506
|
+
"askedBy": "hub-console",
|
|
507
|
+
"note": "Enforced only while the native mode is ask. In auto-edit and yolo Qwen may allow a call without sending a request.",
|
|
508
|
+
"evidence": [
|
|
509
|
+
{ "file": "src/hub/daemon.ts", "needle": "actionEnforcement" }
|
|
510
|
+
]
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"id": "qwen.hub-tools.hub-turn",
|
|
514
|
+
"kinds": ["qwen"],
|
|
515
|
+
"environments": ["terminal", "orca", "headless"],
|
|
516
|
+
"form": "any",
|
|
517
|
+
"point": "hub-tools",
|
|
518
|
+
"asks": "None for the hub's own tools during a turn the hub delivered: an exact mcp__agent-hub__<name> title is auto-approved.",
|
|
519
|
+
"controlledBy": [],
|
|
520
|
+
"hubSeesBeforeRun": "yes",
|
|
521
|
+
"askedBy": "none",
|
|
522
|
+
"note": "In the dual-output TUI this holds only while a hub-delivered turn is started and hub-owned. A turn the person types is covered by qwen.hub-tools.personal-turn.",
|
|
523
|
+
"evidence": [
|
|
524
|
+
{ "file": "src/hub/daemon.ts", "needle": "autoApprove: name => !stopping && HUB_TOOL_TITLES.has(name)" },
|
|
525
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "Only a hub turn asks the hub." }
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
{
|
|
529
|
+
"id": "qwen.hub-tools.personal-turn",
|
|
530
|
+
"kinds": ["qwen"],
|
|
531
|
+
"environments": ["terminal", "orca"],
|
|
532
|
+
"form": "tui",
|
|
533
|
+
"point": "hub-tools",
|
|
534
|
+
"asks": "Qwen's own TUI prompt, if any, for a hub tool called during a turn the person typed. The hub neither auto-approves nor asks.",
|
|
535
|
+
"controlledBy": ["native.qwen"],
|
|
536
|
+
"hubSeesBeforeRun": "no",
|
|
537
|
+
"askedBy": "native-tui",
|
|
538
|
+
"note": "The adapter returns before autoApprove, the action gate and onPermission unless the turn is started and hub-owned. unknown: whether Qwen's native mode prompts for the hub's tools at all.",
|
|
539
|
+
"unknowns": ["whether Qwen's own mode prompts for hub tools"],
|
|
540
|
+
"evidence": [
|
|
541
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "During the person's own turn the TUI prompt is theirs" }
|
|
542
|
+
]
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
"id": "qwen.tool-approval.tui-hub-turn",
|
|
546
|
+
"kinds": ["qwen"],
|
|
547
|
+
"environments": ["terminal", "orca"],
|
|
548
|
+
"form": "tui",
|
|
549
|
+
"point": "tool-approval",
|
|
550
|
+
"asks": "During a turn the hub delivered: Qwen's can_use_tool request, shown on the hub console. Answering in the Qwen terminal first withdraws the hub's pending approval.",
|
|
551
|
+
"controlledBy": ["native.qwen", "approvals.timeout_s"],
|
|
552
|
+
"hubSeesBeforeRun": "yes",
|
|
553
|
+
"askedBy": "native-and-hub",
|
|
554
|
+
"note": "Only while the turn is started and hub-owned. Explicit only (ahub qwen --mode tui), never opened by the hub. A hub denial ends the turn without an answer. unknown: whether permission_modes.qwen changes anything for the TUI, which is launched with --approval-mode default.",
|
|
555
|
+
"unknowns": ["whether permission_modes.qwen changes the dual-output TUI"],
|
|
556
|
+
"evidence": [
|
|
557
|
+
{ "file": "docs/operations.md", "needle": "can_use_tool" },
|
|
558
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "Only a hub turn asks the hub." }
|
|
559
|
+
]
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"id": "qwen.tool-approval.tui-personal-turn",
|
|
563
|
+
"kinds": ["qwen"],
|
|
564
|
+
"environments": ["terminal", "orca"],
|
|
565
|
+
"form": "tui",
|
|
566
|
+
"point": "tool-approval",
|
|
567
|
+
"asks": "During a turn the person typed: Qwen's own TUI prompt only. The hub console is not asked, so the person is not asked twice.",
|
|
568
|
+
"controlledBy": ["native.qwen"],
|
|
569
|
+
"hubSeesBeforeRun": "no",
|
|
570
|
+
"askedBy": "native-tui",
|
|
571
|
+
"evidence": [
|
|
572
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "During the person's own turn the TUI prompt is theirs" }
|
|
573
|
+
]
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
"id": "qwen.classed-action.tui-hub-turn",
|
|
577
|
+
"kinds": ["qwen"],
|
|
578
|
+
"environments": ["terminal", "orca"],
|
|
579
|
+
"form": "tui",
|
|
580
|
+
"point": "classed-action",
|
|
581
|
+
"asks": "During a turn the hub delivered: the same console approval, with the classed title, for a classed call in the dual-output TUI.",
|
|
582
|
+
"controlledBy": ["action_policy", "native.qwen"],
|
|
583
|
+
"hubSeesBeforeRun": "yes",
|
|
584
|
+
"askedBy": "native-and-hub",
|
|
585
|
+
"note": "Only while the turn is started and hub-owned.",
|
|
586
|
+
"evidence": [
|
|
587
|
+
{ "file": "src/hub/daemon.ts", "needle": "onPermission, actionGate: (call, session) => acpActionGate(peer)" },
|
|
588
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "Only a hub turn asks the hub." }
|
|
589
|
+
]
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
"id": "qwen.classed-action.tui-personal-turn",
|
|
593
|
+
"kinds": ["qwen"],
|
|
594
|
+
"environments": ["terminal", "orca"],
|
|
595
|
+
"form": "tui",
|
|
596
|
+
"point": "classed-action",
|
|
597
|
+
"asks": "During a turn the person typed: Qwen's own TUI prompt only. The hub classifies nothing.",
|
|
598
|
+
"controlledBy": ["native.qwen"],
|
|
599
|
+
"hubSeesBeforeRun": "no",
|
|
600
|
+
"askedBy": "native-tui",
|
|
601
|
+
"evidence": [
|
|
602
|
+
{ "file": "src/adapters/qwen-dual.ts", "needle": "During the person's own turn the TUI prompt is theirs" }
|
|
603
|
+
]
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
"id": "jcode.tool-approval.any",
|
|
607
|
+
"kinds": ["jcode"],
|
|
608
|
+
"environments": ["terminal", "orca", "headless"],
|
|
609
|
+
"form": "any",
|
|
610
|
+
"point": "tool-approval",
|
|
611
|
+
"asks": "Jcode's own native policy decides. The hub maps no mode and has no pre-tool approval path, in either form.",
|
|
612
|
+
"controlledBy": ["native.jcode", "peers.<peer>.start_mode"],
|
|
613
|
+
"hubSeesBeforeRun": "no",
|
|
614
|
+
"askedBy": "unknown",
|
|
615
|
+
"note": "permission_modes.jcode is refused by the config loader. unknown: who asks and where, in the TUI and in headless ACP. The source establishes only that the policy is unmanaged by the hub, not that a native TUI prompt appears, and in headless there is no TUI.",
|
|
616
|
+
"unknowns": ["who asks and where, in the TUI form", "who asks and where, in headless ACP"],
|
|
617
|
+
"evidence": [
|
|
618
|
+
{ "file": "src/adapters/definitions/builtin-metadata.ts", "needle": "Jcode native policy is unmanaged" },
|
|
619
|
+
{ "file": "src/hub/permission-mode.ts", "needle": "approvals belong to its native tools" }
|
|
620
|
+
]
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"id": "jcode.classed-action.any",
|
|
624
|
+
"kinds": ["jcode"],
|
|
625
|
+
"environments": ["terminal", "orca", "headless"],
|
|
626
|
+
"form": "any",
|
|
627
|
+
"point": "classed-action",
|
|
628
|
+
"asks": "Nothing from the hub: always-ask is not enforceable for Jcode.",
|
|
629
|
+
"controlledBy": ["action_policy", "native.jcode"],
|
|
630
|
+
"hubSeesBeforeRun": "no",
|
|
631
|
+
"askedBy": "unknown",
|
|
632
|
+
"note": "unknown: whether Jcode asks at all for a classed call, and who, in either form. The hub's side is established: it sees nothing first.",
|
|
633
|
+
"unknowns": ["whether and who asks for a classed call, in either form"],
|
|
634
|
+
"evidence": [
|
|
635
|
+
{ "file": "docs/operations.md", "needle": "Jcode still has no hub pre-tool approval path" }
|
|
636
|
+
]
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"id": "pi.tool-approval.any",
|
|
640
|
+
"kinds": ["pi"],
|
|
641
|
+
"environments": ["terminal", "orca", "headless"],
|
|
642
|
+
"form": "any",
|
|
643
|
+
"point": "tool-approval",
|
|
644
|
+
"asks": "The hub console's approval at the host permit boundary for each model tool call.",
|
|
645
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "approvals.timeout_s", "launch.unattended"],
|
|
646
|
+
"hubSeesBeforeRun": "yes",
|
|
647
|
+
"askedBy": "hub-console",
|
|
648
|
+
"note": "ask-when-needed grants write and edit outside native agent configuration paths and proven read-only shell calls, and other shell and git writes ask. never-ask grants each tool once within the existing sandbox and path guard. Two unanswered requests in a row end the turn, never the peer. Pi's own always grant lives only in that start.",
|
|
649
|
+
"evidence": [
|
|
650
|
+
{ "file": "docs/operations.md", "needle": "Grant each tool once within the existing sandbox/guard" },
|
|
651
|
+
{ "file": "docs/agent-notes/adapters.md", "needle": "Pi and local approvals (#253)" }
|
|
652
|
+
]
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
"id": "pi.classed-action.any",
|
|
656
|
+
"kinds": ["pi"],
|
|
657
|
+
"environments": ["terminal", "orca", "headless"],
|
|
658
|
+
"form": "any",
|
|
659
|
+
"point": "classed-action",
|
|
660
|
+
"asks": "The hub console's approval for a classed call, checked before never-ask, ask-when-needed or Pi's tool-wide grant.",
|
|
661
|
+
"controlledBy": ["action_policy", "approvals.timeout_s"],
|
|
662
|
+
"hubSeesBeforeRun": "yes",
|
|
663
|
+
"askedBy": "hub-console",
|
|
664
|
+
"note": "Not enforced for a Pi without a verified live tool bridge. unattended never answers a classed request.",
|
|
665
|
+
"evidence": [
|
|
666
|
+
{ "file": "src/hub/daemon.ts", "needle": "Pi has no verified live tool bridge" }
|
|
667
|
+
]
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"id": "local.tool-approval.any",
|
|
671
|
+
"kinds": ["local"],
|
|
672
|
+
"environments": ["terminal", "orca", "headless"],
|
|
673
|
+
"form": "headless",
|
|
674
|
+
"point": "tool-approval",
|
|
675
|
+
"asks": "The hub console's approval at the host permit boundary for each model tool call of the hub-native worker.",
|
|
676
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>", "approvals.timeout_s", "launch.unattended"],
|
|
677
|
+
"hubSeesBeforeRun": "yes",
|
|
678
|
+
"askedBy": "hub-console",
|
|
679
|
+
"note": "The worker is headless in every environment, so no terminal is involved. The modes behave as for Pi. A local worker offline cannot be enforced.",
|
|
680
|
+
"evidence": [
|
|
681
|
+
{ "file": "docs/operations.md", "needle": "Pi and local" },
|
|
682
|
+
{ "file": "docs/agent-notes/local-worker.md", "needle": "ToolApproval" }
|
|
683
|
+
]
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
"id": "local.classed-action.any",
|
|
687
|
+
"kinds": ["local"],
|
|
688
|
+
"environments": ["terminal", "orca", "headless"],
|
|
689
|
+
"form": "headless",
|
|
690
|
+
"point": "classed-action",
|
|
691
|
+
"asks": "The hub console's approval for a classed call, checked before any mode grant.",
|
|
692
|
+
"controlledBy": ["action_policy", "approvals.timeout_s"],
|
|
693
|
+
"hubSeesBeforeRun": "yes",
|
|
694
|
+
"askedBy": "hub-console",
|
|
695
|
+
"evidence": [
|
|
696
|
+
{ "file": "src/hub/daemon.ts", "needle": "the local worker is offline" }
|
|
697
|
+
]
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
"id": "agy.tool-approval.tui",
|
|
701
|
+
"kinds": ["agy"],
|
|
702
|
+
"environments": ["terminal", "orca"],
|
|
703
|
+
"form": "tui",
|
|
704
|
+
"point": "tool-approval",
|
|
705
|
+
"asks": "Antigravity's own TUI permission prompts.",
|
|
706
|
+
"controlledBy": ["native.agy"],
|
|
707
|
+
"hubSeesBeforeRun": "no",
|
|
708
|
+
"askedBy": "native-tui",
|
|
709
|
+
"note": "Pull-only and started only by the person's own ahub agy: conductor starts are refused, so terminal.open and Orca never open it. --dangerously-skip-permissions and --unattended are refused until their native mapping is verified.",
|
|
710
|
+
"evidence": [
|
|
711
|
+
{ "file": "src/adapters/agy/definition.ts", "needle": "Antigravity approves tools in its own TUI" }
|
|
712
|
+
]
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
"id": "agy.classed-action.tui",
|
|
716
|
+
"kinds": ["agy"],
|
|
717
|
+
"environments": ["terminal", "orca"],
|
|
718
|
+
"form": "tui",
|
|
719
|
+
"point": "classed-action",
|
|
720
|
+
"asks": "Whatever Antigravity's own TUI asks. The hub classifies nothing for it.",
|
|
721
|
+
"controlledBy": ["native.agy"],
|
|
722
|
+
"hubSeesBeforeRun": "no",
|
|
723
|
+
"askedBy": "native-tui",
|
|
724
|
+
"evidence": [
|
|
725
|
+
{ "file": "src/adapters/agy/definition.ts", "needle": "unmanaged native permission policy" }
|
|
726
|
+
]
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"id": "agy.hub-tools.tui",
|
|
730
|
+
"kinds": ["agy"],
|
|
731
|
+
"environments": ["terminal", "orca"],
|
|
732
|
+
"form": "tui",
|
|
733
|
+
"point": "hub-tools",
|
|
734
|
+
"asks": "Whether Antigravity's TUI asks before calling hub_* tools from its project plugin.",
|
|
735
|
+
"controlledBy": ["native.agy"],
|
|
736
|
+
"hubSeesBeforeRun": "unknown",
|
|
737
|
+
"askedBy": "unknown",
|
|
738
|
+
"note": "unknown: not observable by the hub.",
|
|
739
|
+
"unknowns": ["whether Antigravity's TUI asks before calling hub tools"],
|
|
740
|
+
"evidence": [
|
|
741
|
+
{ "file": "docs/operations.md", "needle": "Optional Antigravity (agy) peer" }
|
|
742
|
+
]
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
"id": "unobserved.hub-tools.any",
|
|
746
|
+
"kinds": ["codex", "jcode", "pi", "local"],
|
|
747
|
+
"environments": ["terminal", "orca", "headless"],
|
|
748
|
+
"form": "any",
|
|
749
|
+
"point": "hub-tools",
|
|
750
|
+
"asks": "Whether the peer asks before calling the hub's own tools.",
|
|
751
|
+
"controlledBy": [],
|
|
752
|
+
"hubSeesBeforeRun": "unknown",
|
|
753
|
+
"askedBy": "unknown",
|
|
754
|
+
"note": "unknown: neither the code nor the docs state it for these kinds. Ask the T0 reviewer or probe it in the T4 receipt.",
|
|
755
|
+
"unknowns": ["whether codex, jcode, pi or local ask before calling the hub's own tools"],
|
|
756
|
+
"evidence": [
|
|
757
|
+
{ "file": "docs/operations.md", "needle": "Permission modes for running peers" }
|
|
758
|
+
]
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
"id": "tui-open.terminal.dual",
|
|
762
|
+
"kinds": ["codex", "kimi", "pi", "jcode"],
|
|
763
|
+
"environments": ["terminal"],
|
|
764
|
+
"form": "tui",
|
|
765
|
+
"point": "tui-open",
|
|
766
|
+
"asks": "Nothing when terminal.open is configured. With none, a hub-made TUI start is refused and names the command to run by hand.",
|
|
767
|
+
"controlledBy": ["terminal.open", "peers.<peer>.start_mode"],
|
|
768
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
769
|
+
"askedBy": "none",
|
|
770
|
+
"note": "start_mode headless avoids the terminal. pi.auto_start starts Pi with the hub through the same path.",
|
|
771
|
+
"evidence": [
|
|
772
|
+
{ "file": "src/hub/terminal-open.ts", "needle": "no terminal.open command is configured" },
|
|
773
|
+
{ "file": "docs/operations.md", "needle": "No provider:" }
|
|
774
|
+
]
|
|
775
|
+
},
|
|
776
|
+
{
|
|
777
|
+
"id": "tui-open.terminal.tui-only",
|
|
778
|
+
"kinds": ["claude"],
|
|
779
|
+
"environments": ["terminal"],
|
|
780
|
+
"form": "tui",
|
|
781
|
+
"point": "tui-open",
|
|
782
|
+
"asks": "Nothing when terminal.open is configured. With none, a hub-made Claude start is refused and names the command to run by hand.",
|
|
783
|
+
"controlledBy": ["terminal.open"],
|
|
784
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
785
|
+
"askedBy": "none",
|
|
786
|
+
"note": "Claude has no start_mode: its TUI is its only form (a headless implementer is a separately declared instance).",
|
|
787
|
+
"evidence": [
|
|
788
|
+
{ "file": "src/hub/terminal-open.ts", "needle": "no terminal.open command is configured" }
|
|
789
|
+
]
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
"id": "tui-open.orca.dual",
|
|
793
|
+
"kinds": ["codex", "kimi", "pi", "jcode"],
|
|
794
|
+
"environments": ["orca"],
|
|
795
|
+
"form": "tui",
|
|
796
|
+
"point": "tui-open",
|
|
797
|
+
"asks": "Nothing from the hub: Orca creates the terminal. Native prompts of the peer then appear in that terminal.",
|
|
798
|
+
"controlledBy": ["terminal.open", "peers.<peer>.start_mode"],
|
|
799
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
800
|
+
"askedBy": "none",
|
|
801
|
+
"note": "A configured terminal.open template wins over Orca.",
|
|
802
|
+
"evidence": [
|
|
803
|
+
{ "file": "src/cli/terminal-recovery.ts", "needle": "[\"terminal\", \"create\", \"--worktree\"" },
|
|
804
|
+
{ "file": "docs/operations.md", "needle": "Orca, when the hub runs in an Orca worktree" }
|
|
805
|
+
]
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
"id": "tui-open.orca.tui-only",
|
|
809
|
+
"kinds": ["claude"],
|
|
810
|
+
"environments": ["orca"],
|
|
811
|
+
"form": "tui",
|
|
812
|
+
"point": "tui-open",
|
|
813
|
+
"asks": "Nothing from the hub: Orca creates the terminal. Claude's native prompts then appear in that terminal.",
|
|
814
|
+
"controlledBy": ["terminal.open"],
|
|
815
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
816
|
+
"askedBy": "none",
|
|
817
|
+
"note": "Orca runs Claude under per-profile CLAUDE_CONFIG_DIR homes (issue #999). ahub setup does not read CLAUDE_CONFIG_DIR, so unknown: whether the hub plugin is installed in each profile home.",
|
|
818
|
+
"unknowns": ["whether the hub plugin is installed in each Orca Claude profile home"],
|
|
819
|
+
"evidence": [
|
|
820
|
+
{ "file": "src/cli/terminal-recovery.ts", "needle": "[\"terminal\", \"create\", \"--worktree\"" },
|
|
821
|
+
{ "file": "src/adapters/definitions/builtin-metadata.ts", "needle": "configDirEnv: \"CLAUDE_CONFIG_DIR\"" }
|
|
822
|
+
]
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
"id": "hub.mode-confirmation",
|
|
826
|
+
"kinds": ["hub"],
|
|
827
|
+
"environments": ["terminal", "orca", "headless"],
|
|
828
|
+
"form": "any",
|
|
829
|
+
"point": "mode-confirmation",
|
|
830
|
+
"asks": "A separate console y (or the peer id typed in the dashboard, or --yes in a terminal) before a never-ask mode takes effect.",
|
|
831
|
+
"controlledBy": ["permission_modes.<peer>", "permission.<peer>"],
|
|
832
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
833
|
+
"askedBy": "hub-console",
|
|
834
|
+
"note": "A never-ask default from an untracked config.local.json starts in ask and appears as a pending console question at hub start. There is no boot --yes bypass, and automatic config effects stop at ask-when-needed. Only the person sets a mode: no hub tool or conductor tool can.",
|
|
835
|
+
"evidence": [
|
|
836
|
+
{ "file": "docs/operations.md", "needle": "Only its separate console y enables that default" }
|
|
837
|
+
]
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"id": "hub.approval-expiry",
|
|
841
|
+
"kinds": ["hub"],
|
|
842
|
+
"environments": ["terminal", "orca", "headless"],
|
|
843
|
+
"form": "any",
|
|
844
|
+
"point": "approval-expiry",
|
|
845
|
+
"asks": "Nothing: an unanswered request is cancelled as a denial after approvals.timeout_s. It decides what an unwatched run does when a prompt appears.",
|
|
846
|
+
"controlledBy": ["approvals.timeout_s"],
|
|
847
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
848
|
+
"askedBy": "hub-console",
|
|
849
|
+
"evidence": [
|
|
850
|
+
{ "file": "docs/operations.md", "needle": "An unanswered request is cancelled after `approvals.timeout_s`" }
|
|
851
|
+
]
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
"id": "hub.unattended",
|
|
855
|
+
"kinds": ["hub"],
|
|
856
|
+
"environments": ["terminal", "orca", "headless"],
|
|
857
|
+
"form": "any",
|
|
858
|
+
"point": "unattended",
|
|
859
|
+
"asks": "ahub up --unattended answers unclassed ACP, Pi and local requests allow-once on its own. A classed request and a person-only request are never answered for the person.",
|
|
860
|
+
"controlledBy": ["launch.unattended", "action_policy"],
|
|
861
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
862
|
+
"askedBy": "none",
|
|
863
|
+
"note": "Per-launch native flags are separate: ahub claude --unattended skips every Claude permission check, hooks included, and ahub codex --unattended is refused under a non-ask mode.",
|
|
864
|
+
"evidence": [
|
|
865
|
+
{ "file": "src/hub/daemon.ts", "needle": "a classed call is never answered for the person, `--unattended` included" }
|
|
866
|
+
]
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
"id": "hub.settings-raise",
|
|
870
|
+
"kinds": ["hub"],
|
|
871
|
+
"environments": ["terminal", "orca", "headless"],
|
|
872
|
+
"form": "any",
|
|
873
|
+
"point": "settings-raise",
|
|
874
|
+
"asks": "Raising tasks.auto_pull or a permission default needs a settings session (ahub ui --settings) or the person's own terminal. An ordinary dashboard session cannot. The configured conductor may set only thirteen live keys, which include task_sweep.enabled and task_sweep.auto_reassign but not tasks.auto_pull and no permission key.",
|
|
875
|
+
"controlledBy": ["tasks.auto_pull", "task_sweep.auto_reassign", "permission_modes.<peer>"],
|
|
876
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
877
|
+
"askedBy": "hub-console",
|
|
878
|
+
"evidence": [
|
|
879
|
+
{ "file": "src/hub/settings.ts", "needle": "can widen what agents do without asking" },
|
|
880
|
+
{ "file": "docs/operations.md", "needle": "Only the thirteen existing live registry keys" }
|
|
881
|
+
]
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
"id": "hub.task-pull",
|
|
885
|
+
"kinds": ["hub"],
|
|
886
|
+
"environments": ["terminal", "orca", "headless"],
|
|
887
|
+
"form": "any",
|
|
888
|
+
"point": "task-flow",
|
|
889
|
+
"asks": "No person prompt. With tasks.auto_pull off, a freed slot waits until a planner assigns or pulls a card. On, the hub pulls the top explicitly reserved ready card, never an unreserved or PII one.",
|
|
890
|
+
"controlledBy": ["tasks.auto_pull"],
|
|
891
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
892
|
+
"askedBy": "none",
|
|
893
|
+
"evidence": [
|
|
894
|
+
{ "file": "src/hub/tasks.ts", "needle": "autoPullAdmitted" },
|
|
895
|
+
{ "file": "src/hub/settings.ts", "needle": "tasks.auto_pull" }
|
|
896
|
+
]
|
|
897
|
+
},
|
|
898
|
+
{
|
|
899
|
+
"id": "hub.task-sweep",
|
|
900
|
+
"kinds": ["hub"],
|
|
901
|
+
"environments": ["terminal", "orca", "headless"],
|
|
902
|
+
"form": "any",
|
|
903
|
+
"point": "task-flow",
|
|
904
|
+
"asks": "No person prompt. The idle sweep is off by default. When on with auto_reassign off, it posts notices and a reassignment suggestion and a planner or the person moves the task.",
|
|
905
|
+
"controlledBy": ["task_sweep.enabled", "task_sweep.auto_reassign"],
|
|
906
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
907
|
+
"askedBy": "none",
|
|
908
|
+
"evidence": [
|
|
909
|
+
{ "file": "src/hub/task-sweep.ts", "needle": "auto_reassign" }
|
|
910
|
+
]
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
"id": "hub.merge",
|
|
914
|
+
"kinds": ["hub"],
|
|
915
|
+
"environments": ["terminal", "orca", "headless"],
|
|
916
|
+
"form": "any",
|
|
917
|
+
"point": "merge",
|
|
918
|
+
"asks": "With auto_merge off (the default) the hub merges nothing: the person or the configured conductor runs ahub sdlc merge. On, the guarded merge runs after an approving review at the current head. A release PR always needs the person's consent.",
|
|
919
|
+
"controlledBy": ["sdlc.auto_merge"],
|
|
920
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
921
|
+
"askedBy": "none",
|
|
922
|
+
"note": "The merge argv is a closed shape (squash, match-head-commit), never --admin.",
|
|
923
|
+
"evidence": [
|
|
924
|
+
{ "file": "src/hub/sdlc-merge.ts", "needle": "mergeArgv" },
|
|
925
|
+
{ "file": "docs/sdlc.md", "needle": "auto_merge" }
|
|
926
|
+
]
|
|
927
|
+
},
|
|
928
|
+
{
|
|
929
|
+
"id": "hub.release",
|
|
930
|
+
"kinds": ["hub"],
|
|
931
|
+
"environments": ["terminal", "orca", "headless"],
|
|
932
|
+
"form": "any",
|
|
933
|
+
"point": "release",
|
|
934
|
+
"asks": "The person's ahub sdlc authorize-release in a person's terminal, and the pre-push guard that fails closed on version tags. Agents and delegated calls cannot authorize.",
|
|
935
|
+
"controlledBy": ["release.authorize"],
|
|
936
|
+
"hubSeesBeforeRun": "not-applicable",
|
|
937
|
+
"askedBy": "hub-console",
|
|
938
|
+
"evidence": [
|
|
939
|
+
{ "file": "docs/operations.md", "needle": "Agents and delegated live-test calls cannot authorize" }
|
|
940
|
+
]
|
|
941
|
+
}
|
|
942
|
+
]
|
|
943
|
+
}
|