arkgate 4.1.1 → 4.2.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 +81 -3
- package/README.md +15 -4
- package/bin/ark-check-runtime.mjs +16 -5
- package/bin/ark-mcp-runtime.mjs +766 -64
- package/bin/lib/agent-gates.mjs +1 -0
- package/bin/lib/ci-and-commands.mjs +16 -7
- package/bin/lib/codex-home.mjs +90 -8
- package/bin/lib/design-smells.mjs +71 -9
- package/bin/lib/doctor-plan.mjs +36 -36
- package/bin/lib/effective-contract-load.mjs +73 -9
- package/bin/lib/enforcement-state.mjs +1 -1
- package/bin/lib/gate-files.mjs +441 -9
- package/bin/lib/github-enforcement.mjs +16 -3
- package/bin/lib/hook-templates.mjs +12 -11
- package/bin/lib/html-report-evolution.mjs +114 -0
- package/bin/lib/html-report.mjs +11 -89
- package/bin/lib/import-resolve.mjs +33 -11
- package/bin/lib/install-activation.mjs +87 -0
- package/bin/lib/install-migrate.mjs +66 -50
- package/bin/lib/managed-upgrade.mjs +10 -41
- package/bin/lib/mcp-adoption.mjs +15 -5
- package/bin/lib/pilot-loop.mjs +25 -8
- package/bin/lib/project-identity.mjs +103 -0
- package/bin/lib/report-snapshot-context.mjs +28 -0
- package/bin/lib/resident-hook.mjs +33 -9
- package/bin/lib/rules-inventory.mjs +100 -8
- package/bin/lib/skill-install.mjs +272 -22
- package/bin/lib/skill-write.mjs +899 -0
- package/bin/lib/start-preview.mjs +84 -1
- package/bin/lib/upgrade-command.mjs +2 -5
- package/dist/index.cjs +13 -13
- package/dist/index.d.ts +194 -2
- package/dist/index.js +13 -13
- package/docs/README.md +5 -3
- package/docs/agent-guide.md +110 -14
- package/docs/ai-gates.md +103 -18
- package/docs/assets/ark-write-gate.svg +2 -2
- package/docs/enthusiast/how-to-agent-gates.md +6 -0
- package/docs/package-surface.md +14 -9
- package/docs/product-voice.md +13 -1
- package/package.json +3 -1
- package/schemas/ark.project-identity.schema.json +116 -0
- package/server.json +2 -2
- package/templates/skills/ark-adopt.md +9 -0
- package/templates/skills/ark-architect.md +12 -2
- package/templates/skills/ark-autopilot.md +9 -0
- package/templates/skills/ark-contract.md +11 -1
- package/templates/skills/ark-coverage.md +9 -0
- package/templates/skills/ark-explain.md +13 -1
- package/templates/skills/ark-explore.md +9 -0
- package/templates/skills/ark-fix.md +10 -1
- package/templates/skills/ark-loop.md +11 -2
- package/templates/skills/ark-place.md +17 -6
- package/templates/skills/ark-runtime.md +8 -0
- package/templates/skills/ark-think.md +14 -2
- package/templates/skills/ark-upgrade.md +9 -0
package/docs/README.md
CHANGED
|
@@ -52,13 +52,15 @@ These are **not** the day-to-day product path. They stay in the repo for evidenc
|
|
|
52
52
|
| Area | Path |
|
|
53
53
|
|------|------|
|
|
54
54
|
| Release notes (by version) | [releases/](releases/) · [CHANGELOG.md](../CHANGELOG.md) |
|
|
55
|
-
| Epic plans (seeded + shipped) | [plans/](plans/) ·
|
|
55
|
+
| Epic plans (seeded + shipped) | [plans/](plans/) · active: [workspace identity and activation truth](plans/workspace-identity-activation-truth/README.md) (`WI01`, 4.2.0 corrective minor) |
|
|
56
56
|
| Claims audit | [audit/claims-matrix.md](audit/claims-matrix.md) |
|
|
57
57
|
| Field adoption kit (scaffolding, not closed) | [field/](field/) |
|
|
58
58
|
| Runtime hardening (experimental) | [production-hardening.md](production-hardening.md) |
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
Prepared candidate: [releases/4.2.0.md](releases/4.2.0.md) (`arkgate@4.2.0`, not published).
|
|
61
|
+
|
|
62
|
+
Current published: [releases/4.1.1.md](releases/4.1.1.md) (`arkgate@4.1.1` on npm `latest`).
|
|
63
|
+
Previous: [releases/4.1.0.md](releases/4.1.0.md) (`arkgate@4.1.0`).
|
|
62
64
|
Previous major: [releases/4.0.0.md](releases/4.0.0.md) (`arkgate@4.0.0`).
|
|
63
65
|
Config: [configuration.md](configuration.md) · Agent skills dual-plane: [agent-guide.md](agent-guide.md).
|
|
64
66
|
|
package/docs/agent-guide.md
CHANGED
|
@@ -46,6 +46,13 @@ status context name. Never claim Cursor/Codex/OpenCode hard write. Soft-write al
|
|
|
46
46
|
the project is unfinished; doctor keeps it as an environment residual. See [ai-gates.md](ai-gates.md)
|
|
47
47
|
and the README host matrix.
|
|
48
48
|
|
|
49
|
+
**MCP project identity (4.2.0):** before trusting project-specific MCP evidence, call
|
|
50
|
+
`ark_identity` with `project.expectedRoot` set to the exact project's absolute root. Reuse that
|
|
51
|
+
root plus the returned `projectIdentity.projectId` on every later Ark tool call. A descendant
|
|
52
|
+
path is authoritative only when that matching project id is also supplied. Only
|
|
53
|
+
`binding.status: "matched"` with `authoritative: true` is authoritative; calls that omit the
|
|
54
|
+
expectation remain compatible but are explicitly `unverified`.
|
|
55
|
+
|
|
49
56
|
## Architecture playbook and `ark-check --recommend`
|
|
50
57
|
|
|
51
58
|
Before generating project structure, agents should read the **tool-agnostic application
|
|
@@ -112,6 +119,10 @@ baseline. Do not `--reset-origin` unless the user explicitly wants a new baselin
|
|
|
112
119
|
`ark-check --report --no-archive` still creates `origin.*` on the first report (or on an explicit
|
|
113
120
|
reset) and refreshes `latest.*`; it skips only the timestamped JSON file under
|
|
114
121
|
`.ark/reports/history/`.
|
|
122
|
+
Snapshots record best-effort, shell-free Git provenance (`HEAD`, attached branch, and dirty
|
|
123
|
+
worktree state). Evolution keeps raw metrics visible across ArkGate upgrades, but an Ark score
|
|
124
|
+
delta is comparable—and therefore rendered—only when origin and current snapshots use the same
|
|
125
|
+
ArkGate version.
|
|
115
126
|
|
|
116
127
|
Once the **raw** graph has zero violations (the baseline is deliberately ignored) and governed
|
|
117
128
|
coverage is at least 50%, `ark-check --ratchet-cores` changes `optional: true` to
|
|
@@ -130,7 +141,9 @@ brownfield Align/Stabilize + seed Shape B. `/ark-loop` = plan A only. Empty plan
|
|
|
130
141
|
“architecture healthy” if design-weak residual remains. Full routing table: full-install
|
|
131
142
|
`AGENTS.md` / [README expert skills](../README.md#expert-skills-escapes--not-onboarding).
|
|
132
143
|
|
|
133
|
-
**Design fitness (3.0.1+ / Phase Q 3.0.3):** after edges are clean, doctor can still
|
|
144
|
+
**Design fitness (3.0.1+ / Phase Q 3.0.3):** after checked edges are clean, doctor can still
|
|
145
|
+
report **SUGGEST / ADAPT / ENFORCE · design-weak** using the mode it actually observed; a weak
|
|
146
|
+
design does not imply that enforcement is active.
|
|
134
147
|
|
|
135
148
|
```bash
|
|
136
149
|
npx ark-check --doctor --json # designFitness, designSmells[].outcome, postGreenPath, goldenPattern, pilotLoop
|
|
@@ -145,7 +158,10 @@ npx ark-check --doctor --fail-on-new-smells --base-ref origin/main --json # opt-
|
|
|
145
158
|
**Pilot loop (Q04):** when design-weak, `pilotLoop.nextPilot` is **one** extraction card
|
|
146
159
|
(pilot target, move, success, kill-switch). Apply **that one pilot only**, then re-doctor.
|
|
147
160
|
Success = reduced smell evidence on pilot paths; residual outside the pilot may remain.
|
|
148
|
-
Never
|
|
161
|
+
Never select seed/fixture/demo/migration/generated files as god-module pilots. A real UI business
|
|
162
|
+
rule moves Domain → Application → UI; local permission/UI-state helpers are not selected by their
|
|
163
|
+
`canEdit`-style name alone. Never multi-pilot batch; never mechanical-safe; never claim healthy
|
|
164
|
+
finished while design-weak.
|
|
149
165
|
|
|
150
166
|
**AI-velocity evidence (Q05):** deterministic fixture bench (no live LLM) compares the same
|
|
151
167
|
feature add on design-weak vs golden-path trees. Run `npm run eval:ai-velocity`; metric is
|
|
@@ -456,7 +472,7 @@ npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok,antigra
|
|
|
456
472
|
|------|-----------------|-------------|
|
|
457
473
|
| Claude Code | `.claude/settings.json` hook + `.mcp.json` / `claude mcp add` | `.claude/skills/<name>/SKILL.md` |
|
|
458
474
|
| Cursor | `.cursor/mcp.json` + `.cursor/rules/ark.mdc` | `.cursor/commands/` |
|
|
459
|
-
| OpenAI Codex | `.codex/config.toml` (project primary, relative `--root
|
|
475
|
+
| OpenAI Codex | `.codex/config.toml` (project primary, relative `--root .`; configured on disk is not runtime-active until restart + `ark_identity` match); optional legacy `$CODEX_HOME/config.toml` fallback uses absolute roots and scoped secondaries — see [ai-gates.md](ai-gates.md) | **Repo:** `.agents/skills/<name>/SKILL.md`; **home:** `$CODEX_HOME/skills/<name>/SKILL.md` (`--codex-home`) |
|
|
460
476
|
| **Grok Build** | `.grok/hooks/ark-write-gate.json` + `.grok/config.toml` / `.mcp.json` | `.grok/skills/<name>/SKILL.md` |
|
|
461
477
|
| Google Antigravity | `.agents/hooks.json` (+ `GEMINI.md` for shared Gemini consumers) | `.agents/skills/<name>/SKILL.md` |
|
|
462
478
|
| OpenCode | `opencode.json` MCP (`type: local`; advisory) | `.opencode/skills/<name>/SKILL.md` |
|
|
@@ -464,6 +480,11 @@ npx arkgate-check --install-agent-gates --tools claude,cursor,codex,grok,antigra
|
|
|
464
480
|
This is a path reference, not a guarantee table. Full copy-paste setups:
|
|
465
481
|
[ai-gates.md](ai-gates.md). Skill inventory: main
|
|
466
482
|
[README](../README.md#other-skills-only-when-you-need-them).
|
|
483
|
+
When several repositories share one machine, repo catalogs stay pinned and isolated; unchanged
|
|
484
|
+
skill bodies are not rewritten for a version stamp. The optional `$CODEX_HOME/skills` catalog is
|
|
485
|
+
monotonic across ArkGate 4.2.0+ installers. Pre-4.2 binaries ignore its metadata and lock, so
|
|
486
|
+
upgrade legacy repos before they write the optional home catalog. See
|
|
487
|
+
[AI gates — Codex skill catalog](ai-gates.md#codex-skill-catalog-skillmd-not-flat-prompts).
|
|
467
488
|
|
|
468
489
|
For an optional executable adoption check, copy the shipped template into a Vitest/Jest suite
|
|
469
490
|
after installing ArkGate:
|
|
@@ -846,17 +867,41 @@ required, and `behavioralCompletion` remains `not-evaluated` even when structure
|
|
|
846
867
|
npx ark-mcp --root . --config ark.config.json [--manifest ark.manifest.json]
|
|
847
868
|
```
|
|
848
869
|
|
|
849
|
-
- **
|
|
850
|
-
`ark.manifest().toJSON()` via `--manifest`. Without that flag, the resource uses every active
|
|
851
|
-
layer and the effective rules from `ark.config.json`; the strict 11-layer profile is the
|
|
852
|
-
fallback only when the project config declares no layers.
|
|
870
|
+
- **Identity handshake** — first call `ark_identity` with:
|
|
853
871
|
|
|
854
|
-
|
|
872
|
+
```json
|
|
873
|
+
{
|
|
874
|
+
"project": {
|
|
875
|
+
"expectedRoot": "/absolute/exact-project-root"
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
Then reuse both `expectedRoot` and the returned `projectIdentity.projectId` as
|
|
881
|
+
`project.expectedProjectId` on every later Ark tool call. `expectedProjectId` without
|
|
882
|
+
`expectedRoot` can detect the wrong id, but it remains non-authoritative because it does not
|
|
883
|
+
prove the current workspace root. The first handshake requires the exact project root; a
|
|
884
|
+
contained descendant becomes authoritative only on later calls that also send the matching
|
|
885
|
+
project id.
|
|
886
|
+
- **Tool `ark_manifest`** — authoritative contract discovery after the identity handshake.
|
|
887
|
+
Serve an exported `ark.manifest().toJSON()` via `--manifest`. Without that flag, the tool uses
|
|
888
|
+
every active layer and the effective rules from `ark.config.json`; the strict 11-layer profile
|
|
889
|
+
is the fallback only when the project config declares no layers. Call it with the same root +
|
|
890
|
+
project id expectation.
|
|
891
|
+
- **Resource `ark://manifest`** — compatibility discovery for standard MCP `resources/read`
|
|
892
|
+
clients. That protocol request has no portable project-expectation field, so Ark always marks
|
|
893
|
+
this resource `unverified` and non-authoritative. It never substitutes for `ark_manifest` in
|
|
894
|
+
a project verdict.
|
|
895
|
+
|
|
896
|
+
The server exposes these twelve tools. Every tool accepts the additive
|
|
897
|
+
`project: { expectedRoot, expectedProjectId? }` input:
|
|
855
898
|
|
|
856
899
|
| Tool | Primary input and purpose |
|
|
857
900
|
|------|---------------------------|
|
|
901
|
+
| `ark_identity` | `{ project: { expectedRoot, expectedProjectId? } }`: return the canonical root/config, stable project id, contract identity, and live runtime identity; use it before every other project-bound surface. |
|
|
902
|
+
| `ark_manifest` | No non-project args: return the machine-readable architecture contract with an authoritative binding after the identity handshake. |
|
|
858
903
|
| `validate_code` | `{ source, layer?, filePath? }`: validate one snippet; infer the layer from `filePath` when possible; return an error result when invalid. |
|
|
859
|
-
| `ark_check` | `{ strict?, baseline? }`: run the full project architecture check
|
|
904
|
+
| `ark_check` | `{ strict?, baseline? }`: run the full project architecture check. `verdict` separates `identity`, `completeness`, `graph`, `coverage`, `gates`, and `overallOk`; no individual green fact substitutes for the combined verdict. |
|
|
860
905
|
| `ark_policy_delta` | `{ baseConfig, candidateConfig?, acknowledgement? }`: classify a complete contract transition; never edits the contract. |
|
|
861
906
|
| `ark_coverage` | No args: report per-layer counts, every unclassified file, unmatched layers, and missing rule edges. |
|
|
862
907
|
| `ark_place` | `{ filePath?, description? }`: resolve or propose a governed home and return its import/global constraints. |
|
|
@@ -864,8 +909,55 @@ The server exposes these nine tools:
|
|
|
864
909
|
| `ark_prepare_change` | `{ changes, changeMap? }`: preflight one complete create/update/delete batch in memory; never writes files. |
|
|
865
910
|
| `ark_recommend` | No args: return the deterministic application-shape plan used by `ark-check --recommend --json`. |
|
|
866
911
|
| `ark_suggest_include` | No args: propose TypeScript/JavaScript include roots from workspaces and nested packages. |
|
|
912
|
+
| `ark_rules_inventory` | No args: inventory possible intra-layer rules using configured layer evidence when available; test/fixture/seed/migration surfaces and narrow technical constants are excluded from extraction pilots. Counts are not a score. |
|
|
913
|
+
|
|
914
|
+
Every project-bound tool success, tool error, and JSON-RPC error data carries:
|
|
915
|
+
|
|
916
|
+
```json
|
|
917
|
+
{
|
|
918
|
+
"projectIdentity": {
|
|
919
|
+
"schemaVersion": "1.0",
|
|
920
|
+
"projectId": "sha256:…",
|
|
921
|
+
"resolvedRoot": "/absolute/project",
|
|
922
|
+
"resolvedConfigPath": "/absolute/project/ark.config.json",
|
|
923
|
+
"arkgateVersion": "4.2.0",
|
|
924
|
+
"contractHash": "sha256:…",
|
|
925
|
+
"contractSource": "project",
|
|
926
|
+
"runtimeId": "process-specific",
|
|
927
|
+
"processStartedAt": "2026-07-30T00:00:00.000Z"
|
|
928
|
+
},
|
|
929
|
+
"binding": {
|
|
930
|
+
"status": "matched",
|
|
931
|
+
"authoritative": true
|
|
932
|
+
},
|
|
933
|
+
"authoritative": true
|
|
934
|
+
}
|
|
935
|
+
```
|
|
867
936
|
|
|
868
|
-
|
|
937
|
+
`projectId` stays stable across process restarts and contract edits; `runtimeId` and
|
|
938
|
+
`processStartedAt` identify this live process. Binding states are:
|
|
939
|
+
|
|
940
|
+
- `matched` — canonical `expectedRoot` is the exact project root, or it is a contained
|
|
941
|
+
descendant and the caller also supplied the matching project id; `authoritative` is `true`;
|
|
942
|
+
- `unverified` — no expectation was supplied, or only the id matched; callable for legacy
|
|
943
|
+
clients, but `authoritative` is `false`;
|
|
944
|
+
- `mismatch` — invalid/wrong root or id; `authoritative` is `false` and Ark returns
|
|
945
|
+
`PROJECT_ROOT_MISMATCH`, `PROJECT_ID_MISMATCH`, or `INVALID_PROJECT_EXPECTATION`.
|
|
946
|
+
|
|
947
|
+
Roots, configs, manifests, TypeScript configs, and project-bound tool paths are canonicalized
|
|
948
|
+
through real paths. A config or file path outside the bound project fails before Ark returns
|
|
949
|
+
placement, golden-pattern, Layers, or ArkRules evidence. The MCP process never retargets itself
|
|
950
|
+
from tool input; disjoint projects need disjoint processes. The compatibility `ark://manifest`
|
|
951
|
+
resource also carries the identity envelope, but its binding is always `unverified` and
|
|
952
|
+
non-authoritative.
|
|
953
|
+
|
|
954
|
+
For `ark_check`, treat `verdict.overallOk` as the combined control-plane fact. It can be true only
|
|
955
|
+
when the binding is matched, analysis is complete, the graph is valid, coverage is complete
|
|
956
|
+
(non-empty, 100% governed, zero unclassified files), and both local-write and CI-merge gate state
|
|
957
|
+
are active. The underlying CLI fields remain present for diagnosis, but are not an authoritative
|
|
958
|
+
whole-project green on their own.
|
|
959
|
+
|
|
960
|
+
Current diagnostic envelopes use schema `1.4` and require `mode`,
|
|
869
961
|
`completeness: "complete" | "partial" | "unavailable"`, and structured
|
|
870
962
|
`completenessReasons`. Resolved results expose `policyHash`, `resolverIdentity`, `factsHash`, and
|
|
871
963
|
`candidateTreeHash`; MCP `ark_check` mirrors CLI `ok`. Single-file `validate_code`,
|
|
@@ -875,7 +967,9 @@ preflight. Consumer-owned 1.0/1.1/1.2 `AdapterResult` values remain accepted by
|
|
|
875
967
|
|
|
876
968
|
For hook-based enforcement, `ark-mcp --hook` runs one-shot: it reads a PreToolUse payload
|
|
877
969
|
from stdin, validates the post-edit file content, and exits `2` with violations on stderr
|
|
878
|
-
to block the write (`0` to allow).
|
|
970
|
+
to block the write (`0` to allow). `--root-env` accepts a prioritized comma-separated
|
|
971
|
+
environment-variable list; ArkGate uses the first populated value and otherwise keeps
|
|
972
|
+
the explicit `--root` fallback. Working Claude Code configuration
|
|
879
973
|
(`.claude/settings.json`):
|
|
880
974
|
|
|
881
975
|
```json
|
|
@@ -887,7 +981,7 @@ to block the write (`0` to allow). Working Claude Code configuration
|
|
|
887
981
|
"hooks": [
|
|
888
982
|
{
|
|
889
983
|
"type": "command",
|
|
890
|
-
"command": "npx ark-mcp --hook --root
|
|
984
|
+
"command": "npx ark-mcp --hook --root . --root-env CLAUDE_PROJECT_DIR"
|
|
891
985
|
}
|
|
892
986
|
]
|
|
893
987
|
}
|
|
@@ -896,8 +990,8 @@ to block the write (`0` to allow). Working Claude Code configuration
|
|
|
896
990
|
}
|
|
897
991
|
```
|
|
898
992
|
|
|
899
|
-
Register the server itself in `.mcp.json` so the agent can
|
|
900
|
-
`validate_code` on demand:
|
|
993
|
+
Register the server itself in `.mcp.json` so the agent can handshake with `ark_identity`, call
|
|
994
|
+
`ark_manifest`, and use `validate_code` on demand:
|
|
901
995
|
|
|
902
996
|
```json
|
|
903
997
|
{
|
|
@@ -910,6 +1004,8 @@ Register the server itself in `.mcp.json` so the agent can read `ark://manifest`
|
|
|
910
1004
|
On Claude/Grok, the installed PreToolUse hook makes matched writes an enforced checkpoint. MCP
|
|
911
1005
|
registration by itself remains advisory on every host because the agent must call the tool.
|
|
912
1006
|
|
|
1007
|
+
Decision rationale: [ADR 0017 — MCP verdicts require explicit project identity](adr/0017-mcp-project-identity-binding.md).
|
|
1008
|
+
|
|
913
1009
|
## Experimental runtime kernel workflow (not the default path)
|
|
914
1010
|
|
|
915
1011
|
This section is for adopters who **opt into** the experimental `@arkgate/runtime` / kernel surfaces.
|
package/docs/ai-gates.md
CHANGED
|
@@ -85,9 +85,12 @@ supported smells on touched paths. Companion plan JSON: `plan.patternBets[]` wit
|
|
|
85
85
|
[package-surface.md](package-surface.md) and [brownfield-adoption.md](brownfield-adoption.md) §6.
|
|
86
86
|
|
|
87
87
|
If your project uses Codex or Grok, treat MCP registration as part of the default
|
|
88
|
-
setup, not an optional extra. Ark works best when the agent can
|
|
88
|
+
setup, not an optional extra. Ark works best when the agent can call `ark_manifest`
|
|
89
89
|
before it writes code; that is the fast path to avoiding architecture drift during
|
|
90
|
-
generation.
|
|
90
|
+
generation. Registration on disk is not runtime proof: after the host starts the server, call
|
|
91
|
+
`ark_identity` with `project.expectedRoot` set to the exact project's absolute root and require
|
|
92
|
+
a `matched`, authoritative binding. Then call `ark_manifest` with that root plus the returned
|
|
93
|
+
project id before using project evidence.
|
|
91
94
|
|
|
92
95
|
## Claude Code — hook (recommended, hard block)
|
|
93
96
|
|
|
@@ -158,7 +161,7 @@ Add to your project's `.claude/settings.json`:
|
|
|
158
161
|
"hooks": [
|
|
159
162
|
{
|
|
160
163
|
"type": "command",
|
|
161
|
-
"command": "npx ark-mcp --hook --hook-repair --root
|
|
164
|
+
"command": "npx ark-mcp --hook --hook-repair --root . --root-env CLAUDE_PROJECT_DIR --config ark.config.json"
|
|
162
165
|
}
|
|
163
166
|
]
|
|
164
167
|
}
|
|
@@ -173,7 +176,7 @@ That's the whole setup. Try asking the agent to import a persistence adapter fro
|
|
|
173
176
|
Ark architecture gate blocked this write to src/domain/order.ts (layer: DomainModel):
|
|
174
177
|
- [FORBIDDEN_PATTERN] Forbidden pattern matched: /from ['"].*\/(infra|adapters|persistence|db)/i (line 1)
|
|
175
178
|
- [FORBIDDEN_IMPORT] Forbidden import target: "../adapters/persistence/pg-order-repository". (line 1)
|
|
176
|
-
Fix the violations and retry.
|
|
179
|
+
Fix the violations and retry. After ark_identity matches, call ark_manifest with the same project expectation for the authoritative contract.
|
|
177
180
|
```
|
|
178
181
|
|
|
179
182
|
## Claude Code — SessionStart context injection (know the rules before the first token)
|
|
@@ -191,7 +194,7 @@ injects into the agent's context at session start:
|
|
|
191
194
|
"hooks": [
|
|
192
195
|
{
|
|
193
196
|
"type": "command",
|
|
194
|
-
"command": "npx ark-mcp --session-context --root
|
|
197
|
+
"command": "npx ark-mcp --session-context --root . --root-env CLAUDE_PROJECT_DIR --config ark.config.json"
|
|
195
198
|
}
|
|
196
199
|
]
|
|
197
200
|
}
|
|
@@ -207,7 +210,7 @@ Ark architecture contract governs this project (ark.config.json is authoritative
|
|
|
207
210
|
Layers:
|
|
208
211
|
- DomainModel: src/domain/** — forbidden globals: fetch, process, Date.now, Math.random
|
|
209
212
|
- PersistenceAdapters: src/adapters/persistence/**
|
|
210
|
-
Rules: 10 denied layer edge(s). Full contract:
|
|
213
|
+
Rules: 10 denied layer edge(s). Full authoritative contract: ark_manifest after ark_identity.
|
|
211
214
|
Baseline: 3 frozen violation(s) — only NEW violations fail; do not add to them.
|
|
212
215
|
After edits run: npx ark-check --root . --config ark.config.json --strict
|
|
213
216
|
```
|
|
@@ -219,9 +222,20 @@ prints nothing and exits 0, so non-Ark projects are untouched.
|
|
|
219
222
|
|
|
220
223
|
## Claude Code — MCP server (contract discovery + on-demand validation)
|
|
221
224
|
|
|
222
|
-
The MCP server exposes
|
|
223
|
-
|
|
224
|
-
|
|
225
|
+
The MCP server exposes tools plus one compatibility resource that agents can use proactively
|
|
226
|
+
(not an exhaustive list — `tools/list` is authoritative):
|
|
227
|
+
|
|
228
|
+
- **`ark_identity`** (tool) — returns the canonical project/config identity and this live MCP
|
|
229
|
+
runtime identity. Call it first with
|
|
230
|
+
`{ "project": { "expectedRoot": "/absolute/exact-project-root" } }`, then reuse the same root
|
|
231
|
+
and returned `projectIdentity.projectId` as `project.expectedProjectId` on later calls. A
|
|
232
|
+
descendant path is authoritative only when that matching id is also supplied.
|
|
233
|
+
- **`ark_manifest`** (tool) — returns the authoritative machine-readable architecture contract
|
|
234
|
+
(layers + rules) after the identity handshake. Call it with the same project expectation before
|
|
235
|
+
generating code.
|
|
236
|
+
- **`ark://manifest`** (resource) — compatibility-only discovery for standard MCP
|
|
237
|
+
`resources/read`. Because that request has no portable project-expectation field, this resource
|
|
238
|
+
is always `unverified` and non-authoritative.
|
|
225
239
|
- **`validate_code`** (tool) — validates a snippet against the architecture on demand (the write-path gate). May return additive **`autoPatch`** (W1) for mechanical-safe import-type rewrites.
|
|
226
240
|
- **`ark_prepare_write`** (tool) — **W2:** place + constrain + validate + optional autoPatch + judgmentBrief + contentHash in one call (composes `ark_place` + write gate).
|
|
227
241
|
- **`ark_prepare_change`** (tool) — **T02–T05:** read-only atomic create/update/delete preflight with cross-file edge/cycle findings and candidate fingerprints. Optional `changeMap` accepts strict schema `1.0` intent and returns its hash plus satisfied/missing/contradictory/unplanned structural convergence; behavioral completion is not evaluated. Omission is supported. MCP registration remains advisory unless the host makes invocation non-bypassable.
|
|
@@ -235,7 +249,20 @@ The MCP server exposes a resource and tools agents can use proactively (not an e
|
|
|
235
249
|
- **`ark_check`** (tool) — runs the full architecture check and returns structured violations (applies the baseline automatically when one exists).
|
|
236
250
|
- **`ark_coverage`** (tool) — per-layer file counts, the full unclassified-file list, and layers whose patterns match nothing.
|
|
237
251
|
|
|
238
|
-
|
|
252
|
+
Every Ark tool accepts the additive `project` expectation. Project-bound tool successes and
|
|
253
|
+
errors carry `projectIdentity`, `binding`, and `authoritative`. A legacy call with no expectation
|
|
254
|
+
stays callable but returns `binding.status: "unverified"` and `authoritative: false`; a wrong
|
|
255
|
+
root/id returns a mismatch before project evidence. Absolute project paths and
|
|
256
|
+
config/manifest/tsconfig inputs are real-path contained inside the server root. The process never
|
|
257
|
+
switches projects from input. The compatibility resource carries the same identity envelope but
|
|
258
|
+
is always unverified/non-authoritative.
|
|
259
|
+
|
|
260
|
+
`ark_check.verdict` keeps `identity`, `completeness`, `graph`, `coverage`, and `gates` separate.
|
|
261
|
+
Only `overallOk` combines them; a graph-clean result cannot paint an unverified binding,
|
|
262
|
+
incomplete analysis, empty/partial coverage, or inactive gates green.
|
|
263
|
+
|
|
264
|
+
Tools appear in the agent's tool list automatically — no skill or doc-reading needed — so the
|
|
265
|
+
agent can query the contract instead of shelling out and parsing.
|
|
239
266
|
|
|
240
267
|
```bash
|
|
241
268
|
claude mcp add ark -- npx ark-mcp --root . --config ark.config.json
|
|
@@ -283,7 +310,8 @@ alwaysApply: true
|
|
|
283
310
|
Before writing or editing any TypeScript source file, call the `validate_code`
|
|
284
311
|
tool from the `ark` MCP server with the full post-edit file content and its
|
|
285
312
|
path. If it reports violations, fix them before writing. The architecture
|
|
286
|
-
contract is available
|
|
313
|
+
contract is available authoritatively from `ark_manifest` after `ark_identity`
|
|
314
|
+
matches. `ark://manifest` is compatibility-only and always unverified.
|
|
287
315
|
```
|
|
288
316
|
|
|
289
317
|
Your repository backstop in Cursor is CI: `ark-check` fails its check on anything that slips
|
|
@@ -295,8 +323,9 @@ Recommended for Ark projects.
|
|
|
295
323
|
|
|
296
324
|
Codex 0.123+ dispatches `PreToolUse` for the native `apply_patch` handler. Ark installs
|
|
297
325
|
`.codex/hooks.json` with `ApplyPatch|apply_patch|Write|Edit|MultiEdit` aliases and reconstructs
|
|
298
|
-
every added or updated file in a multi-file patch before allowing it. The hook
|
|
299
|
-
|
|
326
|
+
every added or updated file in a multi-file patch before allowing it. The hook passes
|
|
327
|
+
`--root . --root-env CODEX_PROJECT_DIR`: ArkGate reads the environment directly without
|
|
328
|
+
POSIX shell expansion and safely falls back to the hook working directory.
|
|
300
329
|
|
|
301
330
|
This hook is best-effort in Codex Code Mode: some hosts execute deferred nested `apply_patch`
|
|
302
331
|
calls without dispatching the project `PreToolUse` event. ArkGate therefore does not treat the
|
|
@@ -330,8 +359,45 @@ command = "npx"
|
|
|
330
359
|
args = ["arkgate-mcp", "--root", ".", "--config", "ark.config.json"]
|
|
331
360
|
```
|
|
332
361
|
|
|
333
|
-
|
|
334
|
-
|
|
362
|
+
This file means **configured on disk**, not active. Install and compact
|
|
363
|
+
`ark start --tools codex --json` therefore report the setup-time state explicitly:
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
{
|
|
367
|
+
"runtimeActivation": {
|
|
368
|
+
"configuredOnDisk": true,
|
|
369
|
+
"restartRequired": true,
|
|
370
|
+
"runtimeObserved": false,
|
|
371
|
+
"identityMatch": "unverified",
|
|
372
|
+
"active": false
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Then **restart Codex** — it does not hot-load MCP servers — and call:
|
|
378
|
+
|
|
379
|
+
```json
|
|
380
|
+
{
|
|
381
|
+
"tool": "ark_identity",
|
|
382
|
+
"arguments": {
|
|
383
|
+
"project": {
|
|
384
|
+
"expectedRoot": "/absolute/exact-project-root"
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The live response must say `binding.status: "matched"` and `authoritative: true`. Reuse its
|
|
391
|
+
`projectIdentity.projectId` with the same root on every subsequent Ark call, starting with
|
|
392
|
+
`ark_manifest`. A missing `ark_identity` or `ark_manifest` means the process is from an older
|
|
393
|
+
ArkGate build; restart the host and use the workspace-local CLI until the new server answers. A
|
|
394
|
+
mismatch means Codex is connected to another project's process; do not use its contract,
|
|
395
|
+
placement, Layers, ArkRules, or check evidence.
|
|
396
|
+
|
|
397
|
+
Setup-time `runtimeActivation` remains intentionally conservative: the installer/doctor cannot
|
|
398
|
+
observe a later MCP conversation from files alone. The matched `ark_identity` response is the
|
|
399
|
+
runtime observation for that caller and live process; it does not mutate the setup JSON.
|
|
400
|
+
`.codex/config.toml` by itself never upgrades `runtimeObserved` or `active`.
|
|
335
401
|
|
|
336
402
|
Codex uses the best-effort local patch hook plus advisory MCP for discovery/validation and
|
|
337
403
|
`ark-check` as the hard merge backstop. Register all three as soon as the repo is adopted.
|
|
@@ -359,9 +425,11 @@ writes a scoped secondary table:
|
|
|
359
425
|
| Doctor: primary points at another permanent project | gap id `codex-home-multi-project` (warn if no secondary yet and session host is unknown/Codex; **info + `deferred`** when the session host is known and not Codex — e.g. Grok/Claude/Cursor; info if a scoped secondary is already present) |
|
|
360
426
|
| When using Codex: refresh home skills | `ark-check --install-agent-gates --skills-only --codex-home --force` |
|
|
361
427
|
|
|
362
|
-
When a valid project `.codex/config.toml` exists,
|
|
363
|
-
|
|
364
|
-
|
|
428
|
+
When a valid project `.codex/config.toml` exists, it is the expected binding, but files alone
|
|
429
|
+
cannot prove which already-running process answered. Doctor therefore keeps an unrelated home
|
|
430
|
+
primary as collision evidence until the live `ark_identity` matches; it does not label that home
|
|
431
|
+
entry as the active project. Without a project binding, doctor surfaces the legacy multi-project
|
|
432
|
+
state directly. **Deferred (fix when using Codex):**
|
|
365
433
|
non-temp Codex-home gaps (`codex-home-multi-project`, stale `$CODEX_HOME/skills`) are
|
|
366
434
|
severity **info**, marked `deferred: true`, and omitted from doctor **Primary next action** /
|
|
367
435
|
**Also** list (formerly “Top actions”) when the session host is known and not Codex —
|
|
@@ -381,6 +449,23 @@ Flat `.codex/prompts/*.md` files are **not** the invocable skill catalog. Instal
|
|
|
381
449
|
repo catalog above so AGENTS.md `/ark-*` references match what Codex can load. After install,
|
|
382
450
|
Ark verifies those references against each selected host catalog.
|
|
383
451
|
|
|
452
|
+
**Several repos on one machine:** repo catalogs are independent and follow each repository's
|
|
453
|
+
locally installed ArkGate package. A managed upgrade rewrites a repo skill only when its normalized
|
|
454
|
+
body changes; a package-version stamp alone is a no-op. The optional home catalog is shared, so
|
|
455
|
+
ArkGate 4.2.0+ installation is monotonic there: an older bundled source cannot replace a newer
|
|
456
|
+
managed home skill, even with `--force`. A pre-4.2 binary ignores the catalog/lock protocol and
|
|
457
|
+
can still overwrite those files, so upgrade every legacy repo before it runs `--codex-home`
|
|
458
|
+
(especially with `--force`). Identical content is idempotent, and preserved customization still
|
|
459
|
+
follows the explicit force contract. The shared skill only routes the workflow; project evidence remains
|
|
460
|
+
bound to the repo through `ark_identity`. Ark records the shared catalog in
|
|
461
|
+
`$CODEX_HOME/skills/.arkgate-catalog.json`, writes a durable
|
|
462
|
+
`.arkgate-catalog.pending.json` floor before mutations, and serializes concurrent installs.
|
|
463
|
+
Doctor suppresses home refresh gaps only when the maximum valid committed/pending floor is newer
|
|
464
|
+
than the repo package; an equal pending version remains actionable for recovery, and corrupt
|
|
465
|
+
metadata never counts as a floor. When a newer package retires a skill, Ark removes it only if the
|
|
466
|
+
bytes still match the prior managed identity; customized retired content is preserved and
|
|
467
|
+
released from Ark ownership.
|
|
468
|
+
|
|
384
469
|
**Parity & honesty (doctor / install):**
|
|
385
470
|
|
|
386
471
|
- Doctor distinguishes **missing / stale / legacy-prompts-only** for repo (`.agents/skills`) and
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
<text x="24" y="152" fill="#f85149" font-weight="bold">✗ Ark architecture gate blocked this write to src/domain/order.ts (layer: DomainModel):</text>
|
|
19
19
|
<text x="40" y="174" fill="#f85149">- [FORBIDDEN_IMPORT] Forbidden import target: "../adapters/persistence/pg-order-repository".</text>
|
|
20
|
-
<text x="24" y="196" fill="#8b949e">Fix the violations and retry. The architecture contract is available
|
|
21
|
-
<text x="24" y="214" fill="#8b949e">
|
|
20
|
+
<text x="24" y="196" fill="#8b949e">Fix the violations and retry. The architecture contract is available through</text>
|
|
21
|
+
<text x="24" y="214" fill="#8b949e">the project-bound ark_manifest MCP tool.</text>
|
|
22
22
|
|
|
23
23
|
<text x="24" y="248" fill="#c9d1d9">● The domain layer can't import persistence adapters. I'll define the port in the</text>
|
|
24
24
|
<text x="24" y="266" fill="#c9d1d9">domain instead and implement it in src/adapters/persistence/.</text>
|
|
@@ -42,6 +42,12 @@ npx arkgate-check --doctor
|
|
|
42
42
|
npx arkgate-check --require-gates
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
`--require-gates` implies strict config validation. It verifies content, not filenames alone:
|
|
46
|
+
`AGENTS.md` must contain the Ark contract and strict check, MCP registration must launch one Ark
|
|
47
|
+
server with an explicit project root, compact Codex must contain valid project config plus
|
|
48
|
+
SessionStart/PreToolUse Ark hooks, and CI must execute a fail-closed Ark command. Included but
|
|
49
|
+
unclassified source files therefore remain red.
|
|
50
|
+
|
|
45
51
|
Doctor JSON includes `writePath.mode` plus `enforcementLadder`: support, installation, observed
|
|
46
52
|
evidence, covered operations, bypassability, and CI honesty. MCP registration stays advisory.
|
|
47
53
|
|
package/docs/package-surface.md
CHANGED
|
@@ -16,9 +16,9 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
16
16
|
|
|
17
17
|
| Surface | How you use it | Stability notes |
|
|
18
18
|
|---------|----------------|-----------------|
|
|
19
|
-
| **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`) | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend) are stable within a major. Additive fields OK; removals/renames are major. |
|
|
19
|
+
| **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`) | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend) are stable within a major. Additive fields OK; removals/renames are major. In 4.2, `--require-gates` implies strict config and verifies semantic Ark AGENTS, project-rooted MCP/compact Codex registration, and fail-closed CI rather than file presence alone. |
|
|
20
20
|
| **Programmatic gate API** | `import { analyzeProject, loadContract, createAICodeGate, ... } from 'arkgate'` | The root export is the static gate/config/analysis contract listed below. It intentionally contains no runtime-kernel implementation. |
|
|
21
|
-
| **Doctor design fitness (P02+)** | `ark-check --doctor --json` → `doctor.designFitness`, `doctor.designSmells[]` | Additive. Stable smell `id`s: `io-under-application`, `handler-in-persistence`, `god-module`, `domain-logic-in-ui`, `facade-sql-in-routes`, `mixed-pattern-cluster`, `soft-contract`. Y02 extends `handler-in-persistence` to static ES imports/re-exports of framework HTTP surfaces (`next/server`), `defineRoute` calls, and existing handler bodies inside Persistence-role layers or specific persistence paths; `require()` and dynamic `import()` are outside this narrow advisory, and a generic `Infrastructure` role alone is not Persistence. Persistence candidates are filtered and sorted before the bounded content scan so large application prefixes cannot hide the advisory. The detector inspects the first 800 sorted Persistence candidates; later candidates are uninspected, so **absence of a smell is not full-tree proof** above that envelope (incomplete/`partial` analysis also never proves “no smells”). Each smell has `evidence[]`, `fix`, technical `message`, and plain-language **`outcome`** (Q02). Does **not** fail the gate by itself. |
|
|
21
|
+
| **Doctor design fitness (P02+)** | `ark-check --doctor --json` → `doctor.designFitness`, `doctor.designSmells[]` | Additive. Stable smell `id`s: `io-under-application`, `handler-in-persistence`, `god-module`, `domain-logic-in-ui`, `facade-sql-in-routes`, `mixed-pattern-cluster`, `soft-contract`. Y02 extends `handler-in-persistence` to static ES imports/re-exports of framework HTTP surfaces (`next/server`), `defineRoute` calls, and existing handler bodies inside Persistence-role layers or specific persistence paths; `require()` and dynamic `import()` are outside this narrow advisory, and a generic `Infrastructure` role alone is not Persistence. Persistence candidates are filtered and sorted before the bounded content scan so large application prefixes cannot hide the advisory. The detector inspects the first 800 sorted Persistence candidates; later candidates are uninspected, so **absence of a smell is not full-tree proof** above that envelope (incomplete/`partial` analysis also never proves “no smells”). **4.2 feedback hardening:** mode labels preserve the observed SUGGEST/ADAPT/ENFORCE state; a local permission/UI-state `canEdit` name alone is not a domain smell; real UI business rules route Domain → Application → UI; seed/fixture/demo/migration/generated files are not god-module pilots. Each smell has `evidence[]`, `fix`, technical `message`, and plain-language **`outcome`** (Q02). Does **not** fail the gate by itself. |
|
|
22
22
|
| **Post-green path (Q01)** | `doctor.postGreenPath`, `doctor.primaryNextAction`, `doctor.healthyFinishedForbidden` | Additive when `designFitness.designWeak`. Single Shape door (`id: clarify-for-ai`): explore shape-focus → dual-plan B → autopilot only with OK. Never empty plan A = healthy finished. |
|
|
23
23
|
| **Golden pattern (Q03)** | Optional `.ark/golden-pattern.json`; doctor JSON `doctor.goldenPattern`; MCP `ark_place` / `ark_prepare_write` → `goldenPattern` | Additive, **advisory for NEW code only**. Required fields: `name`, `norm`; optional `newCodeHome`, `examplePath`, `schemaVersion`. **Absent is normal** (no claim). Never ENFORCE; never clears design-weak. Malformed → `invalid: true`, not silent guidance. |
|
|
24
24
|
| **Plan pattern B (P03+)** | `ark-check --plan --json` → `plan.patternBets[]`, `plan.goal.designWeak` | Additive. Each bet: `id`, `smellId`, `pilot`, `evidence`, `successSignal`, `killSwitch`, **`neverMechanicalSafe: true`**, `class: "judgment"`. **Never** auto-applied by loop/autoPatch; not a `remediationKind` mechanical-safe. `goal.met` remains edge honesty only. |
|
|
@@ -32,10 +32,12 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
32
32
|
| **Capability walls, every adapter (U04+U06)** | CLI scan, pure IR engine, atomic preflight, `ark-mcp --hook` / MCP gate (`capabilityWalls`), ESLint `ark/no-denied-capabilities` | The same opt-in deny set enforces across every surface: hook/MCP and CLI cover ambient + import evidence (symbol-aware); the pure engine, preflight, and ESLint cover the import dimension (documented envelope). Dual depth everywhere: plain port hint (`FIX_HINTS`/`suggestion`) + stable JSON (`ruleId`, `capability`, `fixClass: inject-port`, deterministic `nextAction`). |
|
|
33
33
|
| **Hook-path budgets (U06)** | Repository-only evidence: `npm run bench:hook-path`; `eval/performance/hook-budgets.v1.json`; CI job "Hook-path end-to-end budgets" | Measures the COMPLETE pre-tool paths as fresh child processes (hook cold/warm, doctor cold) at 1k/10k. D5 method locked: ceilings are Linux-baseline p95 + fixed headroom, set once per cycle, never ratcheted; scenarios without a recorded baseline stay in RECORDING mode and cannot fail CI. |
|
|
34
34
|
| **Governance weight (W02)** | `ark-check --doctor --json` → `doctor.contractHealth.governanceWeight` | Additive, **advisory only** — raw facts (`declaredLayers`, `populatedLayers`, `governedFiles`, `rules`, `deniedEdges`, `allowedEdges`, `filesPerLayer`, `rulesPerLayer`) plus a fixed comparative band `weight: heavy | typical | light | unknown` and its fixed `note`. Fixed deterministic thresholds: **heavy** = fewer than 25 governed files per declared layer AND (6+ layers OR 4+ well-formed rules per layer); **light** = at most 2 layers over 150+ governed files; **unknown** = no layers or no governed files; everything else is **typical** (banding uses raw ratios; the reported ratios are rounded for display). `notAScore: true` is explicit: never a composite score, ranking, or gate input; the heavy note asks to justify NEW layers/rules and never suggests deleting working ones. Human doctor prints a line only for `heavy`/`light`. |
|
|
35
|
-
| **Report parity (X01)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth"`, nested `governanceWeight`) + layer wall badges | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. |
|
|
36
|
-
| **MCP
|
|
35
|
+
| **Report parity and snapshot evidence (X01/4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. |
|
|
36
|
+
| **MCP project identity (4.2)** | `ark_identity`; `arkgate/schema/project-identity` or `arkgate/schema/ark.project-identity.schema.json`; root API constants/helpers/types | Schema `1.0`. `projectId` hashes canonical root + config path and stays stable across contract edits/restarts; runtime id/start time are separate. Every project-bound tool result and error carries `projectIdentity`, `binding` (`matched` / `unverified` / `mismatch`), and `authoritative`. Canonical out-of-root config/file evidence fails before project data. |
|
|
37
|
+
| **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. |
|
|
37
38
|
| **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds; optional **`arkRules`** map (schema `1.1+`) | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. Absence of `arkRules` is byte-for-byte silent on inter-layer verdicts. |
|
|
38
|
-
| **ArkRules inventory / under-contract (4.0)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. Structure/invariant diagnostics use adapter `1.4` provenance. |
|
|
39
|
+
| **ArkRules inventory / under-contract (4.0; layer context 4.2)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. When configured layer evidence exists it overrides filename role guesses: a Domain file named `handler` is not a controller candidate. Test/fixture/seed/migration/exclusion surfaces plus narrow development-identity, PostgreSQL OID, and technical I/O constants are silent. Without layer evidence, backward-compatible path/content heuristics remain. Structure/invariant diagnostics use adapter `1.4` provenance. |
|
|
40
|
+
| **`arkgate/schema/project-identity`** or **`arkgate/schema/ark.project-identity.schema.json`** | MCP canonical project, contract, runtime, expectation, and binding envelope | Schema `1.0`. Initial `expectedRoot` must be the exact project root. A contained descendant can match only when `expectedProjectId` is also present and correct; id-only matching stays non-authoritative. Mismatch codes are `PROJECT_ROOT_MISMATCH`, `PROJECT_ID_MISMATCH`, and `INVALID_PROJECT_EXPECTATION`. |
|
|
39
41
|
| **Package pin dual-truth (4.0)** | doctor JSON `packageVersionTruth`; upgrade JSON/human note when pin behind CLI | Additive, advisory. Surfaces after `upgrade --no-install` when managed CLI is ahead of package.json. |
|
|
40
42
|
| **Product honesty readiness split (4.1.1 EH)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. |
|
|
41
43
|
| **Policy transition analysis (T01, 3.1.0)** | `analyzePolicyDelta(...)`; MCP `ark_policy_delta`; CLI `--policy-base` / `--policy-base-ref` / `--policy-ack`; check JSON `policyDelta` | Additive schema `1.0`. Classifications and finding ids are deterministic. Weakening/judgment requires an acknowledgement bound to both policy hashes and the exact blocking finding set. |
|
|
@@ -49,7 +51,7 @@ hardening guide remains repository-hosted rather than duplicated in the gate tar
|
|
|
49
51
|
| **`arkgate/schema/arkrules`** or **`arkgate/schema/ark.arkrules.schema.json`** | Per-layer structure sensors + invariant catalog (ADR 0012) | Schema `1.0`. Opt-in via root `arkRules` map (`ark.config` schema `1.1`). |
|
|
50
52
|
| **`arkgate/schema/resolved-candidate-facts`** or **`arkgate/schema/ark.resolved-candidate-facts.schema.json`** | Versioned parity-capable input for `analyzeResolvedProject` / `preflightResolvedChange` | Schema `1.0` is serializable and deterministic. Tooling owns filesystem/compiler resolution; Domain/Kernel validate and evaluate supplied facts without importing those effects. Facts name resolver/compiler inputs, governed files, dependency evidence, completeness reasons, and candidate tree/facts hashes. |
|
|
51
53
|
| **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
|
|
52
|
-
| **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) | **Day zero** is the compact router from `ark start` / `start --apply` + doctor control plane — not the full skill pack. Skill *names* and the guided expert path (`/ark-autopilot` after pack install) are stable; internal skill prose may evolve. **4.0:** all skills except experimental `/ark-runtime` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. |
|
|
54
|
+
| **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) | **Day zero** is the compact router from `ark start` / `start --apply` + doctor control plane — not the full skill pack. Skill *names* and the guided expert path (`/ark-autopilot` after pack install) are stable; internal skill prose may evolve. **4.0:** all skills except experimental `/ark-runtime` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. **4.2:** repo catalogs are content-idempotent; the optional shared Codex home catalog is monotonic across 4.2.0+ installers. Pre-4.2 writers are outside that protocol and must be upgraded first. A durable pending-catalog journal preserves the floor across an interrupted install and is cleared only by its owning same/newer recovery. |
|
|
53
55
|
| **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import rules; loads consumer `ark.config.json`. |
|
|
54
56
|
| **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. |
|
|
55
57
|
| **Package metadata** | `arkgate/package.json` | Stable resource subpath for tooling that needs the installed manifest. |
|
|
@@ -86,6 +88,7 @@ are grouped below.
|
|
|
86
88
|
| Group | Exported runtime values |
|
|
87
89
|
|-------|-------------------------|
|
|
88
90
|
| Metadata and adapter diagnostics | `version`, `ARK_ANALYSIS_RESULT_SCHEMA_VERSION`, `ARK_ANALYSIS_RESULT_SCHEMA`, `createAdapterResult`, `toAdapterDiagnostic` |
|
|
91
|
+
| MCP project identity | `ARK_PROJECT_IDENTITY_SCHEMA_VERSION`, `ARK_PROJECT_IDENTITY_SCHEMA_URL`, `ARK_PROJECT_IDENTITY_SCHEMA`, `PROJECT_EXPECTATION_SCHEMA`, `PROJECT_BINDING_SCHEMA`, `createProjectId`, `createProjectIdentity` |
|
|
89
92
|
| AI snippet gate | `createAICodeGate` |
|
|
90
93
|
| Profiles and config factories | `createArchitectureProfile`, `createArchitectureProfileFromArkConfig`, `createElevenLayerArkConfig`, `elevenLayerProfile` |
|
|
91
94
|
| Analysis and preflight | `loadContract`, `analyzeResolvedProject`, `preflightResolvedChange`, lexical-compatibility `analyzeProject` / `analyzeChange` / `preflightChange`, `analyzePolicyDelta`, `analyzeArchitectureConvergence`, `explainViolation`, `evaluateArchitectureGraph`, `collectAnalysisConfigWarnings`, `detectArchitectureCycles`, `collectForbiddenCapabilityUses`, `extractSemanticDependencies` |
|
|
@@ -98,6 +101,7 @@ The type-only root exports are also semver-supported:
|
|
|
98
101
|
|
|
99
102
|
- Adapter diagnostics: `AdapterDiagnostic`, `AdapterResult`, `AdapterSeverity`,
|
|
100
103
|
`AdapterViolationInput`, `AdapterCompletenessReason`, `AnalysisCompleteness`, `AnalysisMode`.
|
|
104
|
+
- MCP project identity: `ProjectIdentity`, `ProjectExpectation`, `ProjectBinding`.
|
|
101
105
|
- Resolved facts: `ResolvedCandidateFacts`, `ResolvedCandidateFactsInput`, and their
|
|
102
106
|
dependency/file/evidence component types.
|
|
103
107
|
- AI snippet gate: `AICodeGate`, `AICodeGateResult`, `AICodeGateViolation`,
|
|
@@ -190,8 +194,9 @@ production deployment would need to satisfy; it is not a readiness certification
|
|
|
190
194
|
## Release notes (maintainers)
|
|
191
195
|
|
|
192
196
|
Ship notes for a version live under [releases/](https://github.com/pedroknigge/arkgate/tree/main/docs/releases)
|
|
193
|
-
(
|
|
194
|
-
|
|
195
|
-
previous: [4.0.
|
|
197
|
+
(prepared: [4.2.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.2.0.md);
|
|
198
|
+
current published: [4.1.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.1.1.md);
|
|
199
|
+
previous: [4.1.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.1.0.md),
|
|
200
|
+
[4.0.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.0.1.md),
|
|
196
201
|
[4.0.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.0.0.md)).
|
|
197
202
|
Publish path: signed annotated tag → GitHub Release → `publish-npm.yml` (see [CONTRIBUTING.md](https://github.com/pedroknigge/arkgate/blob/main/CONTRIBUTING.md)).
|
package/docs/product-voice.md
CHANGED
|
@@ -22,7 +22,8 @@ because the design space is small and honest.
|
|
|
22
22
|
- **Co-pilot side:** where code belongs, who talks to whom, how; dual plan **A** (edges) +
|
|
23
23
|
**B** (shape); one pilot at a time; never silent judgment codemod; never weaken the contract.
|
|
24
24
|
- **False done is forbidden:** Enforce ≠ elegant design. `design-weak` / residual must not
|
|
25
|
-
read as “healthy finished.” Empty ArkRules inventory is not a score.
|
|
25
|
+
read as “healthy finished.” Empty ArkRules inventory is not a score. MCP configuration on
|
|
26
|
+
disk is not proof that the current process belongs to this project.
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -73,6 +74,12 @@ Examples:
|
|
|
73
74
|
| **compact router** | Default onboarding agent instructions (not the full skill pack) |
|
|
74
75
|
| **hard write** | Non-bypassable PreToolUse block for listed ops (Claude/Grok when installed + trusted) |
|
|
75
76
|
| **advisory write** | MCP/rules coach only (Cursor/Codex at write time) — not a hard block |
|
|
77
|
+
| **project identity** | Stable canonical root + config identity returned by `ark_identity`; separate from contract and process identity |
|
|
78
|
+
| **matched binding** | Live MCP answered for the exact project root, or for a contained descendant together with the matching project id; only this binding is authoritative |
|
|
79
|
+
| **authoritative manifest** | Contract returned by `ark_manifest` after a matched identity handshake |
|
|
80
|
+
| **compatibility manifest resource** | `ark://manifest` through standard `resources/read`; always unverified/non-authoritative because the request cannot portably carry a project expectation |
|
|
81
|
+
| **configured on disk** | Host files name an Ark MCP command; says nothing about which process is currently running |
|
|
82
|
+
| **runtime observed** | A live `ark_identity` response matched this workspace; never infer it from `.codex/config.toml` or hook files |
|
|
76
83
|
| **required CI / status context** | Merge hard boundary when the repository makes the Ark job a **required GitHub status context** (CLI: `arkgate-check --strict-merge` / `ark-check --strict-merge`) |
|
|
77
84
|
| **contract ready** | Project/layers/ArkRules honesty residual clear — not the same as “hard local write” |
|
|
78
85
|
| **environment residual** | Permanent host/provider posture (e.g. soft-write Codex) kept in evidence without forcing global **Not finished** |
|
|
@@ -89,6 +96,8 @@ Examples:
|
|
|
89
96
|
| Keep Suggest on start → doctor | New-here primary is finish `start`, not a competing recommend/architect curriculum |
|
|
90
97
|
| Qualify edge-clean under design-weak | “None on checked edges … design residual remains. Not healthy finished.” |
|
|
91
98
|
| Prefer fail-closed over fake hard | Incomplete analysis, unobserved hooks, and soft MCP never paint as hard green |
|
|
99
|
+
| State project binding before verdict | “Ark MCP matched this workspace; `ark_manifest` evidence is authoritative.” Otherwise: “Ark MCP is configured, but runtime identity is unverified. Restart and call `ark_identity` with the exact project root.” |
|
|
100
|
+
| Keep inventory claims evidence-bound | “Possible rule candidate in the configured Application layer.” A filename or technical constant alone is not Domain evidence. |
|
|
92
101
|
| Honesty clear ≠ architecture healthy | `productHonesty.finished` means residual **architecture** honesty sensors are clear — not a green graph score. Open blocking violations, ADAPT/SUGGEST with debt, dual-truth pin, or design residual keep `unfinished: true`. Permanent soft-write alone does **not**. |
|
|
93
102
|
| Separate CI runtime from provider policy | Successful CI run ≠ required status; GitHub Free plan 403 → `unavailable-plan`, not “CI never ran.” |
|
|
94
103
|
|
|
@@ -105,6 +114,9 @@ Examples:
|
|
|
105
114
|
| “Healthy / done” while design-weak | False done |
|
|
106
115
|
| “Honesty clear” as “architecture finished” | Honesty clear only means residual honesty sensors are quiet; graph/mode debt is separate |
|
|
107
116
|
| “Not finished” solely because host is Codex/Cursor | Soft-write is environment residual; do not paint a green whole-tree project as unfinished architecture |
|
|
117
|
+
| “MCP installed / active” because a config file exists | Say **configured on disk · runtime unverified** until `ark_identity` matches the expected root |
|
|
118
|
+
| Treating an unverified legacy MCP call as authoritative | Compatibility is not proof; require `binding.status: "matched"` and `authoritative: true` |
|
|
119
|
+
| “Handler means controller” / “every constant is a business rule” | ArkRules inventory uses configured layer context and suppresses narrow technical/test evidence; candidates remain prompts for judgment |
|
|
108
120
|
| Conflating CLI name with required status | `ark-check` is the command; the hard boundary is the GitHub required **status context** |
|
|
109
121
|
| “ArkRules prove business correctness” | They enforce *declared* structure/coverage evidence, not arbitrary logic or full semantic proof |
|
|
110
122
|
| “Structure enforced = Domain extraction done” | Structure sensors are **heuristics**; extraction is judgment (`/ark-fix` / pilot) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arkgate",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "ArkGate — architecture co-pilot for AI TypeScript (write gate, CI gate, plan/loop; optional ArkRules)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"./schema/ark.config.schema.json": "./schemas/ark.config.schema.json",
|
|
22
22
|
"./schema/analysis-result": "./schemas/ark.analysis-result.schema.json",
|
|
23
23
|
"./schema/ark.analysis-result.schema.json": "./schemas/ark.analysis-result.schema.json",
|
|
24
|
+
"./schema/project-identity": "./schemas/ark.project-identity.schema.json",
|
|
25
|
+
"./schema/ark.project-identity.schema.json": "./schemas/ark.project-identity.schema.json",
|
|
24
26
|
"./schema/change-map": "./schemas/ark.change-map.schema.json",
|
|
25
27
|
"./schema/ark.change-map.schema.json": "./schemas/ark.change-map.schema.json",
|
|
26
28
|
"./schema/resolved-candidate-facts": "./schemas/ark.resolved-candidate-facts.schema.json",
|