@bradheitmann/odin-sentinel 0.4.4 → 0.4.6
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/AGENTS.md +64 -0
- package/CLAUDE.md +43 -0
- package/README.md +102 -335
- package/dist/src/mcp/server.js +43 -12
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/protocol/schemas.d.ts +2529 -4
- package/dist/src/protocol/schemas.js +214 -18
- package/dist/src/protocol/schemas.js.map +1 -1
- package/dist/src/protocol/service.d.ts +96 -2
- package/dist/src/protocol/service.js +516 -4
- package/dist/src/protocol/service.js.map +1 -1
- package/dist/src/protocol/surface-layout.d.ts +40 -1
- package/dist/src/protocol/surface-layout.js +98 -1
- package/dist/src/protocol/surface-layout.js.map +1 -1
- package/dist/src/protocol/validators.d.ts +3 -0
- package/dist/src/protocol/validators.js +28 -0
- package/dist/src/protocol/validators.js.map +1 -1
- package/dist/src/protocol/version.d.ts +3 -0
- package/dist/src/protocol/version.js +3 -0
- package/dist/src/protocol/version.js.map +1 -1
- package/dist/src/telemetry/config.d.ts +8 -0
- package/dist/src/telemetry/config.js +24 -0
- package/dist/src/telemetry/config.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +5 -5
- package/dist/src/telemetry/index.js +3 -3
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/redactor.js +25 -7
- package/dist/src/telemetry/redactor.js.map +1 -1
- package/dist/src/telemetry/report.d.ts +108 -0
- package/dist/src/telemetry/report.js +83 -3
- package/dist/src/telemetry/report.js.map +1 -1
- package/dist/src/telemetry/submit.d.ts +2 -0
- package/dist/src/telemetry/submit.js +79 -6
- package/dist/src/telemetry/submit.js.map +1 -1
- package/docs/guides/quick-start.md +112 -44
- package/docs/guides/quickstart-prompts.md +65 -0
- package/docs/guides/recommended-starter-team.md +45 -27
- package/docs/reference/client-compatibility.md +20 -43
- package/docs/reference/cost-and-privacy.md +26 -23
- package/docs/reference/distribution.md +40 -55
- package/docs/reference/public-surface-audit.md +35 -114
- package/package.json +19 -4
- package/protocol/SCP.md +8 -1
- package/protocol/bootstrap-skill.md +16 -11
- package/protocol/closeout.yaml +7 -1
- package/protocol/delegation.yaml +1 -1
- package/protocol/model-profiles.yaml +55 -1
- package/protocol/receipts/boot-receipt.yaml +42 -0
- package/protocol/receipts/team-manifest.yaml +41 -0
- package/protocol/roles.yaml +69 -1
- package/protocol/topology.yaml +78 -36
- package/scripts/audit/public-surface.mjs +48 -19
- package/scripts/audit/verify-pack.mjs +294 -27
- package/templates/dev-slice-template.md +56 -0
- package/templates/pm-role-template.md +61 -0
- package/templates/qa-slice-template.md +46 -0
- package/templates/team-manifest-template.yaml +163 -0
|
@@ -7,19 +7,24 @@ updated: 2026-05-11
|
|
|
7
7
|
|
|
8
8
|
# Sentinel Coordination Protocol
|
|
9
9
|
|
|
10
|
+
SCP_PUBLIC_VERSION: 0.4.6
|
|
11
|
+
MIN_COMPATIBLE_CHILD_MCP: 0.4.5
|
|
12
|
+
|
|
13
|
+
Public install readiness: configure the ODIN MCP server, install native skill context where supported or use full prompt fallback, keep governed team roles in CMUX, verify auth/account readiness without printing secrets, smoke-test local inference if used, and validate role compatibility before launch. Private local skill copies may differ intentionally; public release checks compare repo-internal public artifacts only.
|
|
14
|
+
|
|
10
15
|
Use this skill for SCP policy introduction, repo landing, adoption-gate proof, controlled dissemination, active multi-agent control loops, and automated team lifecycle management. SCP is a governance layer for multi-team agent operation; it complements other coordination layers and `AGENTS.md` files where present. It sits above them after activation.
|
|
11
16
|
|
|
12
17
|
## Source Of Truth
|
|
13
18
|
|
|
14
19
|
Master editable source:
|
|
15
20
|
|
|
16
|
-
- the
|
|
21
|
+
- the repository-distributed SCP protocol bundle, or an operator-declared canonical SCP skill source outside this public package.
|
|
17
22
|
|
|
18
|
-
All
|
|
23
|
+
All installed copies are synchronized runtime snapshots, not independent policy forks. Any agent modifying SCP policy must edit the declared source first, then propagate the full skill/protocol bundle to the installed harness targets and verify matching hashes.
|
|
19
24
|
|
|
20
|
-
Use
|
|
25
|
+
Use the operator-declared sync procedure after edits. Do not hand-edit generated runtime copies except as a temporary emergency patch that is immediately backported to the declared source and resynced.
|
|
21
26
|
|
|
22
|
-
Portable curated skill/session records may live under the
|
|
27
|
+
Portable curated skill/session records may live under the declared source, for example `decisions/YYYY-MM-DD-<slug>.md` and optionally `CHANGELOG.md`. Raw audit evidence belongs under `.odin/audit/<session-id>/` or the declared `evidence_path`. Do not create empty folders just to satisfy policy; create `decisions/` only when writing the first curated decision record.
|
|
23
28
|
|
|
24
29
|
## Non-Negotiables
|
|
25
30
|
|
|
@@ -267,7 +272,7 @@ Team PMs and team ODINs may coordinate laterally when needed, but lateral messag
|
|
|
267
272
|
|
|
268
273
|
ODINs must establish a lateral ODIN mesh at bootstrap. `A/EXEC-ODIN` and each `TEAM ODIN` must exchange a short introduction containing role, team, reports-to/coordinates-with chain, team composition, active agent occupants, model/harness/cost tier, known blockers, and next poll time. This is a meta-communication layer, not command authority.
|
|
269
274
|
|
|
270
|
-
During active execution, `A/EXEC-ODIN` should run an ODIN round-robin health pass on a declared cadence, default
|
|
275
|
+
During active execution, `A/EXEC-ODIN` should run an ODIN round-robin health pass on a declared cadence, default 30 seconds unless the user or `EXEC PM` sets another cadence. The executive ODIN starts with its own executive-office health note, sends it to the first team ODIN, and instructs each team ODIN to append its short team composition/status/health note and forward to the next ODIN. The final team ODIN returns the appended packet to `A/EXEC-ODIN`. `A/EXEC-ODIN` compiles the packet, may ask `EXEC DISPATCH` / `SWITCHBOARD` for outstanding communication or waiting-agent notes, then sends a concise status report to `EXEC PM`.
|
|
271
276
|
|
|
272
277
|
ODIN mesh reports must stay short by default and include: team, active occupants, provider/model/harness mix, blocked agents, permission waits, plan-mode/quota/provider failures, role breaches, delivery failures, outstanding relays, and recommended intervention. ODINs may request temporary secondment of another control-plane agent through `EXEC PM` when a PM/ODIN lane fails, but they must not directly reassign agents or expand topology without authorization.
|
|
273
278
|
|
|
@@ -660,7 +665,7 @@ If a control-plane pane begins product/source/test implementation, authors worke
|
|
|
660
665
|
|
|
661
666
|
Editing canonical skills, adapters, runtime skill copies, sync scripts, lifecycle ledgers, branch state, or policy text is a control-plane governance mutation and requires `[SCP-CONTROL-PLANE-MUTATION]` before or with the mutation. ODIN/control-plane roles must not self-accept governance mutations they authored. Acceptance requires independent QA, user ratification, or explicitly named `EXEC PM` ratification after evidence review. An authorized control-plane mutation may be reported as implemented and validation complete, but remains pending ratification until the named ratifier accepts the evidence.
|
|
662
667
|
|
|
663
|
-
Canonical SCP audit, research, ODIN, and control-plane outputs must be written under a durable governance path such as `.odin/
|
|
668
|
+
Canonical SCP audit, research, ODIN, and control-plane outputs must be written under a durable governance path such as `.odin/audit/<audit-id>/` or another declared `evidence_path`. `/tmp` may be used for intermediate captures, cache, delivery-proof repair, or mirrors only. Before `[SCP-FINISH]`, any `/tmp` artifact used for a claim must be copied, summarized, hashed, or explicitly declared non-canonical in the durable audit ledger.
|
|
664
669
|
|
|
665
670
|
`repo_clean` must not be used as shorthand for `governance_clean`. Governance-surface mutations outside the active repository require separate reporting: `external_skill_paths_touched`, `runtime_targets`, `hash_before_after_or_current_hash`, `sync_log_path`, `validation_command`, and `unsynced_or_dirty_runtime_paths`. A clean git worktree proves only the repository checkout state. It does not prove canonical skill, Codex skill, Claude skill, adapter, CMUX runtime, or `/tmp` artifact state.
|
|
666
671
|
|
|
@@ -694,7 +699,7 @@ Continuing past a HALT without remediation is itself a protocol breach. ODIN mus
|
|
|
694
699
|
|
|
695
700
|
### Health Escalation
|
|
696
701
|
|
|
697
|
-
The ODIN mesh runs round-robin health checks per `odin_mesh.
|
|
702
|
+
The ODIN mesh runs round-robin health checks per `odin_mesh.health_round_robin_seconds` (default 30). Per-agent escalation ladder:
|
|
698
703
|
|
|
699
704
|
- **1 missed heartbeat** — warn the affected agent.
|
|
700
705
|
- **2 missed heartbeats** — escalate to `A/EXEC-ODIN` via the mesh aggregator.
|
|
@@ -1410,7 +1415,7 @@ git diff --cached --name-status
|
|
|
1410
1415
|
|
|
1411
1416
|
If upstream is not the declared branch authority, stop before mutation. If `HEAD` and `@{u}` differ for a branch-visible closure claim, stop before mutation.
|
|
1412
1417
|
|
|
1413
|
-
If excluded or out-of-scope debris appears, especially
|
|
1418
|
+
If excluded or out-of-scope debris appears, especially private story-review planning paths, runtime logs, holdout paths, design artifacts, external memory paths, or non-branchable paths, stop and require `EXEC PM` classification before lifecycle mutation or evidence verdict.
|
|
1414
1419
|
|
|
1415
1420
|
Before any `status: Done`, `PHASE: VERIFIED`, `VERDICT: PASS`, active-to-done move, commit, or push, run the slice/evidence validators required by the dispatch. At minimum for slice/evidence work:
|
|
1416
1421
|
|
|
@@ -1432,14 +1437,14 @@ If a closure/evidence hook fails after a lifecycle move or verdict attempt, mark
|
|
|
1432
1437
|
- Read `00-SCP-protocol.md`, especially sections 0, 6, 7, 8, 10, 18, and 20.
|
|
1433
1438
|
|
|
1434
1439
|
2. Land the package, but do not activate it.
|
|
1435
|
-
- Canonical package path:
|
|
1440
|
+
- Canonical package path: the operator-declared governance planning package path.
|
|
1436
1441
|
- Package landing branch: use a deterministic ops branch unless the user supplies another branch.
|
|
1437
1442
|
- Ledger branch: `ops/ledger` for `ledger.yaml`.
|
|
1438
1443
|
- If branch topology is ambiguous or conflicts with current repo state, stop and ask the user.
|
|
1439
1444
|
|
|
1440
1445
|
3. Create adoption-gate scaffolding.
|
|
1441
|
-
-
|
|
1442
|
-
-
|
|
1446
|
+
- governance adoption gate artifact
|
|
1447
|
+
- governance ledger artifact
|
|
1443
1448
|
- `tools/agentic-executive-mgmt/audit/banned-phrases.txt`
|
|
1444
1449
|
- `tools/agentic-executive-mgmt/qa-review/RUBRIC.md`
|
|
1445
1450
|
- Other artifact directories required by the SCP package.
|
package/protocol/closeout.yaml
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
version: 0.
|
|
1
|
+
version: 0.4.6
|
|
2
|
+
active_watch_terminal_states:
|
|
3
|
+
- RELEASED_BY_OPERATOR
|
|
4
|
+
- HANDED_OFF
|
|
5
|
+
- PARKED_IDLE
|
|
6
|
+
- FAILED
|
|
7
|
+
- WATCH_UNSUPPORTED
|
|
2
8
|
modes:
|
|
3
9
|
PARK_FOR_CONTINUITY:
|
|
4
10
|
description: Keep role slots open, park occupants, save handoffs, and preserve continuity.
|
package/protocol/delegation.yaml
CHANGED
|
@@ -1,7 +1,61 @@
|
|
|
1
|
-
version: 0.
|
|
1
|
+
version: 0.4.6
|
|
2
2
|
policy:
|
|
3
3
|
semantics: Recommended starter profiles, not bundled dependencies or availability guarantees.
|
|
4
4
|
runtime_requirement: Users must install and configure their own harnesses. Launchers must verify local harness/model availability before dispatch and apply fallbacks when unavailable.
|
|
5
|
+
governed_launch_probe_required: true
|
|
6
|
+
visible_output_timeout_seconds_default: 60
|
|
7
|
+
provisioning_prompt: Are all intended harnesses provisioned with accounts, plans, API keys, or local inference credentials so they will not malfunction when spun up?
|
|
8
|
+
zero_secret_output: true
|
|
9
|
+
secret_provider_status_only:
|
|
10
|
+
- Doppler
|
|
11
|
+
- 1Password CLI (op)
|
|
12
|
+
- environment variable names
|
|
13
|
+
- direnv
|
|
14
|
+
- mise
|
|
15
|
+
- dotenv-style file presence
|
|
16
|
+
- GitHub auth
|
|
17
|
+
- local provider config files
|
|
18
|
+
model_responsiveness_statuses:
|
|
19
|
+
- MODEL_READY
|
|
20
|
+
- MODEL_SLOW
|
|
21
|
+
- MODEL_STALLED
|
|
22
|
+
- MODEL_REASONING_ONLY
|
|
23
|
+
- STREAMING_PROTOCOL_MISMATCH
|
|
24
|
+
- MODEL_UNREACHABLE
|
|
25
|
+
harness_capabilities:
|
|
26
|
+
Codex:
|
|
27
|
+
can_hydrate_deferred_mcp_tools_at_boot: true
|
|
28
|
+
native_skill_invocation: true
|
|
29
|
+
scp_skill_recommended: true
|
|
30
|
+
Claude Code:
|
|
31
|
+
can_hydrate_deferred_mcp_tools_at_boot: true
|
|
32
|
+
native_skill_invocation: true
|
|
33
|
+
scp_skill_recommended: true
|
|
34
|
+
Droid:
|
|
35
|
+
can_hydrate_deferred_mcp_tools_at_boot: true
|
|
36
|
+
native_skill_invocation: false
|
|
37
|
+
scp_skill_recommended: false
|
|
38
|
+
Goose:
|
|
39
|
+
local_inference_smoke_test_required: true
|
|
40
|
+
visible_content_required_within_seconds: 60
|
|
41
|
+
reasoning_content_only_class: MODEL_REASONING_ONLY
|
|
42
|
+
streaming_mismatch_class: STREAMING_PROTOCOL_MISMATCH
|
|
43
|
+
Crush:
|
|
44
|
+
permission_prompt_class: BLOCKED_BY_PERMISSION
|
|
45
|
+
OpenHands:
|
|
46
|
+
missing_inference_credentials_class: BLOCKED_BY_API_KEY
|
|
47
|
+
provider_config_blocker_class: AUTH_PROVIDER_BLOCKED
|
|
48
|
+
KiloCode:
|
|
49
|
+
login_commands:
|
|
50
|
+
- kilo auth login
|
|
51
|
+
- /connect
|
|
52
|
+
login_blocker_class: BLOCKED_BY_LOGIN
|
|
53
|
+
Pi:
|
|
54
|
+
role_compatibility_failure_class: ROLE_COMPATIBILITY_FAILED
|
|
55
|
+
Aider:
|
|
56
|
+
auth_probe_required: true
|
|
57
|
+
NanoCoder:
|
|
58
|
+
auth_probe_required: true
|
|
5
59
|
profiles:
|
|
6
60
|
A/EXEC-PM:
|
|
7
61
|
model: GPT-5.5-class frontier reasoning model
|
|
@@ -13,6 +13,42 @@ required_fields:
|
|
|
13
13
|
- write_scope
|
|
14
14
|
- evidence_path
|
|
15
15
|
- current_task
|
|
16
|
+
receipt_types:
|
|
17
|
+
- SCP_BOOT_RECEIPT
|
|
18
|
+
- SCP_MIN_BOOT_RECEIPT
|
|
19
|
+
minimum_compatible_mcp_version: 0.4.5
|
|
20
|
+
field_types:
|
|
21
|
+
role: string
|
|
22
|
+
authority_layer: string
|
|
23
|
+
team: string
|
|
24
|
+
terminal_locator: string
|
|
25
|
+
branch: string
|
|
26
|
+
cwd: string
|
|
27
|
+
model_harness: string
|
|
28
|
+
permission_mode: string
|
|
29
|
+
may_implement: boolean
|
|
30
|
+
may_qa_accept: boolean
|
|
31
|
+
reports_to: string
|
|
32
|
+
write_scope: string_array
|
|
33
|
+
evidence_path: string
|
|
34
|
+
current_task: string
|
|
35
|
+
write_scope_policy:
|
|
36
|
+
empty_array_valid_for:
|
|
37
|
+
- no current write assignment
|
|
38
|
+
- may_implement false roles
|
|
39
|
+
- DEV roles in BOOTSTRAPPED_IDLE before assignment
|
|
40
|
+
null_policy: invalid; use [] for unassigned scope
|
|
41
|
+
allowed_lifecycle_states:
|
|
42
|
+
- SURFACE_PROVISIONED
|
|
43
|
+
- BOOTSTRAPPED_IDLE
|
|
44
|
+
- ACTIVE_WATCH
|
|
45
|
+
- VACANT_ROLE_SLOT
|
|
46
|
+
- AGENT_SUBSTITUTION_REQUIRED
|
|
47
|
+
- RELEASED_BY_OPERATOR
|
|
48
|
+
- HANDED_OFF
|
|
49
|
+
- PARKED_IDLE
|
|
50
|
+
- FAILED
|
|
51
|
+
- WATCH_UNSUPPORTED
|
|
16
52
|
recommended_fields:
|
|
17
53
|
- upstream
|
|
18
54
|
- head_sha
|
|
@@ -25,6 +61,12 @@ recommended_fields:
|
|
|
25
61
|
- parent_surface_ref
|
|
26
62
|
- column_index
|
|
27
63
|
- team_letter
|
|
64
|
+
- lifecycle_state
|
|
65
|
+
- mcp_version
|
|
66
|
+
- scp_context_source
|
|
67
|
+
receipt_type_policy:
|
|
68
|
+
SCP_BOOT_RECEIPT: full governed occupant receipt after role/context/readiness are known
|
|
69
|
+
SCP_MIN_BOOT_RECEIPT: minimal bootstrap-only receipt for orientation or pre-dispatch identity proof
|
|
28
70
|
staffing_audit:
|
|
29
71
|
description: >-
|
|
30
72
|
For any role outside the executive office (team != "A"), the boot receipt
|
|
@@ -7,3 +7,44 @@ required_fields:
|
|
|
7
7
|
- model_profile
|
|
8
8
|
- handoff_sources
|
|
9
9
|
- startup_objectives
|
|
10
|
+
role_slot_schema:
|
|
11
|
+
required_fields:
|
|
12
|
+
- role_slot
|
|
13
|
+
- harness
|
|
14
|
+
- readiness_status
|
|
15
|
+
- layout_locator
|
|
16
|
+
- scp_context_source
|
|
17
|
+
layout_locator_fields:
|
|
18
|
+
- workspace
|
|
19
|
+
- pane
|
|
20
|
+
- surface
|
|
21
|
+
readiness_statuses:
|
|
22
|
+
- PASS
|
|
23
|
+
- FAIL
|
|
24
|
+
- WAIVED_BY_EXEC_PM
|
|
25
|
+
- SUBSTITUTION_APPROVED_BY_EXEC_PM
|
|
26
|
+
- NON_GOVERNED_ONE_SHOT_ONLY
|
|
27
|
+
- VACANT_ROLE_SLOT
|
|
28
|
+
watcher_assignments:
|
|
29
|
+
A/EXEC-ODIN:
|
|
30
|
+
watches:
|
|
31
|
+
- executive_office
|
|
32
|
+
- team_odins
|
|
33
|
+
- cross_team_drift
|
|
34
|
+
- missing_receipts
|
|
35
|
+
- stale_proof
|
|
36
|
+
TEAM_ODIN:
|
|
37
|
+
watches:
|
|
38
|
+
- own_team_pm
|
|
39
|
+
- own_dev_slots
|
|
40
|
+
- own_qa_slots
|
|
41
|
+
- own_shadow_slots
|
|
42
|
+
A/EXEC-ASST:
|
|
43
|
+
may_maintain:
|
|
44
|
+
- delivery_proof_ledger
|
|
45
|
+
- heartbeat_ledger
|
|
46
|
+
minimum_compatible_mcp_version: 0.4.5
|
|
47
|
+
scp_context_sources:
|
|
48
|
+
- native sentinel-coordination-protocol skill
|
|
49
|
+
- odin-sentinel MCP at or above minimum version
|
|
50
|
+
- full injected SCP protocol text
|
package/protocol/roles.yaml
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
version: 0.
|
|
1
|
+
version: 0.4.6
|
|
2
2
|
roles:
|
|
3
3
|
EXEC_PM:
|
|
4
4
|
title: EXEC PM
|
|
5
5
|
layer: executive
|
|
6
6
|
may_implement_default: false
|
|
7
7
|
may_qa_accept_default: false
|
|
8
|
+
must_actively_watch: false
|
|
9
|
+
may_intervene: false
|
|
10
|
+
authority_layer: executive
|
|
8
11
|
purpose: Intent, priority, authorization, escalation, and claim framing.
|
|
9
12
|
authority:
|
|
10
13
|
sole_staffing_authority:
|
|
@@ -38,6 +41,28 @@ roles:
|
|
|
38
41
|
layer: meta_control
|
|
39
42
|
may_implement_default: false
|
|
40
43
|
may_qa_accept_default: false
|
|
44
|
+
must_actively_watch: true
|
|
45
|
+
may_intervene: true
|
|
46
|
+
authority_layer: meta_control
|
|
47
|
+
normal_successor_state_after_receipt: ACTIVE_WATCH
|
|
48
|
+
watch_contract:
|
|
49
|
+
default_poll_interval_seconds: 30
|
|
50
|
+
watch_warn_after_seconds: 300
|
|
51
|
+
stalled_after_seconds: 600
|
|
52
|
+
watches:
|
|
53
|
+
- executive_office_health
|
|
54
|
+
- team_odin_health
|
|
55
|
+
- cross_team_drift
|
|
56
|
+
- stale_proof
|
|
57
|
+
- blocked_panes
|
|
58
|
+
- context_exhaustion
|
|
59
|
+
- missing_receipts
|
|
60
|
+
may_inject_corrective_prompts: true
|
|
61
|
+
forbidden:
|
|
62
|
+
- implement product work
|
|
63
|
+
- QA-accept work
|
|
64
|
+
- route business priorities
|
|
65
|
+
- override EXEC PM launch/activation authority
|
|
41
66
|
purpose: Governance health, polling, delivery proof, role boundaries, and closeout hygiene.
|
|
42
67
|
authority:
|
|
43
68
|
intervention_authority:
|
|
@@ -80,24 +105,36 @@ roles:
|
|
|
80
105
|
layer: executive_support
|
|
81
106
|
may_implement_default: false
|
|
82
107
|
may_qa_accept_default: false
|
|
108
|
+
must_actively_watch: false
|
|
109
|
+
may_intervene: false
|
|
110
|
+
authority_layer: executive_support
|
|
83
111
|
purpose: Ledger, reminders, pane inventory, artifact index, and delivery checks.
|
|
84
112
|
EXEC_RSCH:
|
|
85
113
|
title: EXEC RSCH
|
|
86
114
|
layer: research
|
|
87
115
|
may_implement_default: false
|
|
88
116
|
may_qa_accept_default: false
|
|
117
|
+
must_actively_watch: false
|
|
118
|
+
may_intervene: false
|
|
119
|
+
authority_layer: research
|
|
89
120
|
purpose: Read-only strategy, alternatives, context recovery, and risk analysis.
|
|
90
121
|
EXEC_QA:
|
|
91
122
|
title: EXEC QA
|
|
92
123
|
layer: quality
|
|
93
124
|
may_implement_default: false
|
|
94
125
|
may_qa_accept_default: true
|
|
126
|
+
must_actively_watch: false
|
|
127
|
+
may_intervene: false
|
|
128
|
+
authority_layer: quality
|
|
95
129
|
purpose: Independent adversarial audit of process, evidence, closure language, and drift.
|
|
96
130
|
TEAM_PM:
|
|
97
131
|
title: TEAM PM
|
|
98
132
|
layer: pod_control
|
|
99
133
|
may_implement_default: false
|
|
100
134
|
may_qa_accept_default: false
|
|
135
|
+
must_actively_watch: false
|
|
136
|
+
may_intervene: false
|
|
137
|
+
authority_layer: pod_control
|
|
101
138
|
purpose: Pod task routing, worker activation, and reporting.
|
|
102
139
|
forbidden_actions:
|
|
103
140
|
- spawn agents on own pod or any other pod
|
|
@@ -118,6 +155,28 @@ roles:
|
|
|
118
155
|
layer: meta_control
|
|
119
156
|
may_implement_default: false
|
|
120
157
|
may_qa_accept_default: false
|
|
158
|
+
must_actively_watch: true
|
|
159
|
+
may_intervene: true
|
|
160
|
+
authority_layer: meta_control
|
|
161
|
+
normal_successor_state_after_receipt: ACTIVE_WATCH
|
|
162
|
+
watch_contract:
|
|
163
|
+
default_poll_interval_seconds: 30
|
|
164
|
+
watch_warn_after_seconds: 300
|
|
165
|
+
stalled_after_seconds: 600
|
|
166
|
+
watches:
|
|
167
|
+
- own_team_pm
|
|
168
|
+
- own_dev_slots
|
|
169
|
+
- own_qa_slots
|
|
170
|
+
- own_shadow_slots
|
|
171
|
+
reports_to:
|
|
172
|
+
- own TEAM PM
|
|
173
|
+
- A/EXEC-ODIN
|
|
174
|
+
may_inject_corrective_prompts: true
|
|
175
|
+
forbidden:
|
|
176
|
+
- implement product work
|
|
177
|
+
- QA-accept work
|
|
178
|
+
- route business priorities
|
|
179
|
+
- override EXEC PM launch/activation authority
|
|
121
180
|
purpose: Pod health monitoring, polling, blockers, freezes, and lateral ODIN mesh awareness.
|
|
122
181
|
authority:
|
|
123
182
|
intervention_authority:
|
|
@@ -152,16 +211,25 @@ roles:
|
|
|
152
211
|
layer: implementation
|
|
153
212
|
may_implement_default: true
|
|
154
213
|
may_qa_accept_default: false
|
|
214
|
+
must_actively_watch: false
|
|
215
|
+
may_intervene: false
|
|
216
|
+
authority_layer: implementation
|
|
155
217
|
purpose: Bounded implementation inside exact write scope with evidence.
|
|
156
218
|
QA_WORKER:
|
|
157
219
|
title: QA WORKER
|
|
158
220
|
layer: quality
|
|
159
221
|
may_implement_default: false
|
|
160
222
|
may_qa_accept_default: true
|
|
223
|
+
must_actively_watch: false
|
|
224
|
+
may_intervene: false
|
|
225
|
+
authority_layer: quality
|
|
161
226
|
purpose: Independent verification of worker evidence and acceptance criteria.
|
|
162
227
|
SHADOW_REVIEWER:
|
|
163
228
|
title: SHADOW REVIEWER
|
|
164
229
|
layer: review
|
|
165
230
|
may_implement_default: false
|
|
166
231
|
may_qa_accept_default: false
|
|
232
|
+
must_actively_watch: false
|
|
233
|
+
may_intervene: false
|
|
234
|
+
authority_layer: review
|
|
167
235
|
purpose: Independent critique, risk surfacing, and second-pass review.
|
package/protocol/topology.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
version: 0.
|
|
1
|
+
version: 0.4.6
|
|
2
2
|
default_topology:
|
|
3
3
|
executive_office:
|
|
4
4
|
team: A
|
|
@@ -18,39 +18,81 @@ default_topology:
|
|
|
18
18
|
fresh_repo_default_pods: 1
|
|
19
19
|
odin_mesh:
|
|
20
20
|
bootstrap_identity_exchange: true
|
|
21
|
-
|
|
21
|
+
health_round_robin_seconds: 30
|
|
22
22
|
aggregator: A/EXEC-ODIN
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
23
|
+
launch_phases:
|
|
24
|
+
- SURFACE_PROVISIONED
|
|
25
|
+
- OCCUPANT_READINESS
|
|
26
|
+
- OCCUPANT_LAUNCH
|
|
27
|
+
- BOOT_RECEIPT_VALIDATION
|
|
28
|
+
- TEAM_ACTIVATION
|
|
29
|
+
- ACTIVE_WATCH
|
|
30
|
+
readiness_gate:
|
|
31
|
+
minimum_mcp_version: 0.4.5
|
|
32
|
+
cmux_required_for_governed_team: true
|
|
33
|
+
occupant_launch_allowed_when:
|
|
34
|
+
- PASS
|
|
35
|
+
- WAIVED_BY_EXEC_PM
|
|
36
|
+
- SUBSTITUTION_APPROVED_BY_EXEC_PM
|
|
37
|
+
team_activation_allowed_states:
|
|
38
|
+
- BOOTSTRAPPED_IDLE
|
|
39
|
+
- ACTIVE_WATCH
|
|
40
|
+
- VACANT_ROLE_SLOT
|
|
41
|
+
- AGENT_SUBSTITUTION_REQUIRED
|
|
42
|
+
safe_auth_failure_outcomes:
|
|
43
|
+
- choose a different harness
|
|
44
|
+
- receive setup guidance without pasting secrets
|
|
45
|
+
- mark slot VACANT_ROLE_SLOT
|
|
46
|
+
- request EXEC PM-approved substitution
|
|
47
|
+
surface_layout:
|
|
48
|
+
description: >-
|
|
49
|
+
Canonical CMUX surface layout rule for EXEC PM. Governed team bootstrap
|
|
50
|
+
uses human_cmux_quad by default: one CMUX workspace with four panes/regions
|
|
51
|
+
(executive office, Team B pod, Team C pod, blockers/status/intake).
|
|
52
|
+
Legacy columns remain available for compatibility but tab-only layout is
|
|
53
|
+
degraded unless explicitly approved.
|
|
54
|
+
canonical_profile: human_cmux_quad
|
|
55
|
+
human_cmux_quad:
|
|
56
|
+
workspace_policy: A/EXEC-PM remains in the same CMUX workspace as all governed teams
|
|
57
|
+
quadrants:
|
|
58
|
+
A: executive office
|
|
59
|
+
B: Team B pod
|
|
60
|
+
C: Team C pod
|
|
61
|
+
D: blockers/status/intake or overflow
|
|
62
|
+
empty_role_slots_before_launch: true
|
|
63
|
+
reject_tab_only_unless_degraded_mode_approved: true
|
|
64
|
+
reject_split_workspace_without_routing_proof: true
|
|
65
|
+
no_cmux_governed_status: NOT_GOVERNED_NO_CMUX
|
|
66
|
+
legacy_columns:
|
|
67
|
+
description: >-
|
|
68
|
+
Teams arrive as letters (Team A is executive; Team B onward are
|
|
69
|
+
development pods). Columns are equal width. Surfaces stack vertically
|
|
70
|
+
inside a column with at most two surfaces per column. Team A always
|
|
71
|
+
occupies column 0.
|
|
72
|
+
rules:
|
|
73
|
+
max_surfaces_per_column: 2
|
|
74
|
+
column_widths: equal
|
|
75
|
+
exec_team_column: 0
|
|
76
|
+
tall_column_when_odd_team: A
|
|
77
|
+
custodianship:
|
|
78
|
+
sole_custodian: A/EXEC-PM
|
|
79
|
+
includes:
|
|
80
|
+
- cmux new-split
|
|
81
|
+
- cmux new-surface
|
|
82
|
+
- cmux move-surface
|
|
83
|
+
- cmux close-surface
|
|
84
|
+
pre_staffing_gate: >-
|
|
85
|
+
Before adding any agent beyond A/EXEC, EXEC PM must (1) call
|
|
86
|
+
odin.compute_surface_layout for teamCount=N+1, (2) execute the splits
|
|
87
|
+
required to reach that layout via cmux, (3) confirm each new surface
|
|
88
|
+
is empty and addressable via cmux list-pane-surfaces, and only then
|
|
89
|
+
(4) dispatch the spawn to the newly created surface.
|
|
90
|
+
reference_layouts:
|
|
91
|
+
teams_1: "[A]"
|
|
92
|
+
teams_2: "[A] [B]"
|
|
93
|
+
teams_3: "[A] [B/C]"
|
|
94
|
+
teams_4: "[A/D] [B/C]"
|
|
95
|
+
teams_5: "[A] [B/C] [D/E]"
|
|
96
|
+
teams_6: "[A/F] [B/C] [D/E]"
|
|
97
|
+
teams_7: "[A] [B/C] [D/E] [F/G]"
|
|
98
|
+
teams_8: "[A/H] [B/C] [D/E] [F/G]"
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
const PUBLIC_ROOTS = [
|
|
7
|
+
"README.md",
|
|
8
|
+
"AGENTS.md",
|
|
9
|
+
"CLAUDE.md",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"package.json",
|
|
12
|
+
"docs/",
|
|
13
|
+
"protocol/",
|
|
14
|
+
"templates/",
|
|
15
|
+
"plugins/",
|
|
16
|
+
"scripts/audit/"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const EXCLUDED_PREFIXES = [".git/", "dist/", "node_modules/", "project/" + "planning" + "/", "." + "edge-" + "agentic" + "/local/", "tests/"];
|
|
4
20
|
|
|
5
21
|
function walk(dir) {
|
|
6
22
|
return readdirSync(dir).flatMap((entry) => {
|
|
@@ -11,6 +27,11 @@ function walk(dir) {
|
|
|
11
27
|
});
|
|
12
28
|
}
|
|
13
29
|
|
|
30
|
+
export function isPublicAuditFile(file) {
|
|
31
|
+
if (EXCLUDED_PREFIXES.some((prefix) => file.startsWith(prefix))) return false;
|
|
32
|
+
return PUBLIC_ROOTS.some((root) => file === root || file.startsWith(root));
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
function filesToAudit() {
|
|
15
36
|
try {
|
|
16
37
|
const tracked = execFileSync("git", ["ls-files"], {
|
|
@@ -25,19 +46,16 @@ function filesToAudit() {
|
|
|
25
46
|
return `${tracked}\n${untracked}`
|
|
26
47
|
.split("\n")
|
|
27
48
|
.filter(Boolean)
|
|
28
|
-
.filter((file) =>
|
|
49
|
+
.filter((file) => file !== "pnpm-lock.yaml")
|
|
50
|
+
.filter(isPublicAuditFile);
|
|
29
51
|
} catch {
|
|
30
|
-
return walk(".");
|
|
52
|
+
return walk(".").filter(isPublicAuditFile);
|
|
31
53
|
}
|
|
32
54
|
}
|
|
33
55
|
|
|
34
|
-
const publicFiles = filesToAudit();
|
|
35
|
-
|
|
36
|
-
// Install and protocol documentation legitimately references agent harness
|
|
37
|
-
// config directories and tilde home paths. The path-style rules below skip
|
|
38
|
-
// these files; the rest of the rules still apply.
|
|
39
56
|
const BUNDLED_DOC = new Set([
|
|
40
57
|
"README.md",
|
|
58
|
+
"docs/guides/quickstart-prompts.md",
|
|
41
59
|
"protocol/bootstrap-" + "sk" + "ill.md",
|
|
42
60
|
"plugins/sentinel-coordination-protocol/" + "sk" + "ills/sentinel-coordination-protocol/SK" + "ILL.md"
|
|
43
61
|
]);
|
|
@@ -46,7 +64,9 @@ const forbidden = [
|
|
|
46
64
|
{ name: "macOS home path", pattern: new RegExp(`/${"Users"}/[A-Za-z0-9._-]+/`) },
|
|
47
65
|
{ name: "Linux home path", pattern: /\/home\/[A-Za-z0-9._-]+\// },
|
|
48
66
|
{ name: "tilde home path", pattern: /~\//, exemptFiles: BUNDLED_DOC },
|
|
49
|
-
{ name: "local agent config path", pattern: new RegExp(
|
|
67
|
+
{ name: "local agent config path", pattern: new RegExp(`\\.(?:${"codex"}|${"claude"}|${"agents"})(?:/|$)`, "i"), exemptFiles: BUNDLED_DOC },
|
|
68
|
+
{ name: "local evidence path", pattern: new RegExp(`\\.${"edge-" + "agentic"}/local`, "i") },
|
|
69
|
+
{ name: "private planning path", pattern: new RegExp(`project/${"planning"}/`, "i") },
|
|
50
70
|
{
|
|
51
71
|
name: "private project or account marker",
|
|
52
72
|
pattern: new RegExp(
|
|
@@ -57,20 +77,29 @@ const forbidden = [
|
|
|
57
77
|
{ name: "secret-looking assignment", pattern: /(api[_-]?key|secret|token|password)\s*[:=]\s*["'][^"']+["']/i }
|
|
58
78
|
];
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (const file of
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
findings.push(`${file}: ${rule.name}`);
|
|
80
|
+
export function auditPublicSurface(fileTextByPath) {
|
|
81
|
+
const findings = [];
|
|
82
|
+
for (const [file, text] of Object.entries(fileTextByPath)) {
|
|
83
|
+
if (!isPublicAuditFile(file)) continue;
|
|
84
|
+
for (const rule of forbidden) {
|
|
85
|
+
if (rule.exemptFiles?.has(file)) continue;
|
|
86
|
+
if (rule.pattern.test(text)) findings.push(`${file}: ${rule.name}`);
|
|
68
87
|
}
|
|
69
88
|
}
|
|
89
|
+
return findings;
|
|
70
90
|
}
|
|
71
91
|
|
|
72
|
-
|
|
73
|
-
|
|
92
|
+
export function main() {
|
|
93
|
+
const publicFiles = filesToAudit();
|
|
94
|
+
const findings = auditPublicSurface(Object.fromEntries(publicFiles.map((file) => [file, readFileSync(file, "utf8")])));
|
|
95
|
+
|
|
96
|
+
if (findings.length > 0) {
|
|
97
|
+
throw new Error(`Public surface audit failed:\n${findings.join("\n")}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`Public surface audit PASS: ${publicFiles.length} files checked`);
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
|
|
103
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
104
|
+
main();
|
|
105
|
+
}
|