@sleepy_panda_srl/portulan 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +18 -6
  2. package/cli/README.md +56 -4
  3. package/cli/advisory.mjs +167 -53
  4. package/cli/cache-risk.mjs +69 -0
  5. package/cli/comments.mjs +8 -5
  6. package/cli/compile.mjs +492 -146
  7. package/cli/context.mjs +204 -43
  8. package/cli/doctor.mjs +211 -33
  9. package/cli/drills.mjs +32 -7
  10. package/cli/finish.md +34 -0
  11. package/cli/finish.mjs +9 -67
  12. package/cli/form.mjs +35 -19
  13. package/cli/frontmatter.mjs +39 -0
  14. package/cli/gate.mjs +14 -12
  15. package/cli/guidance-files.mjs +335 -0
  16. package/cli/handoff-policy.mjs +76 -0
  17. package/cli/html-entities.mjs +2130 -0
  18. package/cli/import-files.mjs +15 -0
  19. package/cli/index.mjs +77 -24
  20. package/cli/init-preview.mjs +553 -0
  21. package/cli/init.mjs +261 -46
  22. package/cli/instructions-journal.mjs +1185 -0
  23. package/cli/instructions.mjs +332 -57
  24. package/cli/ledger.mjs +123 -37
  25. package/cli/librarian.mjs +103 -19
  26. package/cli/persona-routing.mjs +209 -0
  27. package/cli/plugin-lint.mjs +77 -56
  28. package/cli/portulan.mjs +7 -2
  29. package/cli/recipe-output.mjs +91 -0
  30. package/cli/recipe-runner.md +68 -0
  31. package/cli/recipe-runner.mjs +131 -0
  32. package/cli/recipe-set.mjs +12 -3
  33. package/cli/ritual-contexts.mjs +103 -0
  34. package/cli/sessions.mjs +2 -1
  35. package/cli/spend-analysis.mjs +111 -0
  36. package/cli/spend-offer.md +53 -0
  37. package/cli/spend-offer.mjs +93 -0
  38. package/cli/stop-diagnostics.mjs +114 -0
  39. package/cli/stop-gate.mjs +133 -90
  40. package/cli/stop-policy.mjs +14 -0
  41. package/cli/symbols.mjs +55 -8
  42. package/cli/telemetry.mjs +19 -12
  43. package/cli/upgrade.mjs +62 -44
  44. package/cli/vendor.mjs +210 -126
  45. package/core/operating/context.md +368 -60
  46. package/core/operating/evolution.md +3 -2
  47. package/core/operating/loop.md +9 -4
  48. package/core/operating/sessions.md +6 -15
  49. package/core/personas/README.md +52 -10
  50. package/core/personas/implementer.md +3 -0
  51. package/core/personas/librarian.md +3 -0
  52. package/core/personas/reviewer.md +3 -0
  53. package/core/templates/handoff.md +6 -2
  54. package/evals/ab/personas/README.md +111 -0
  55. package/evals/ab/personas/acquisition.json +330 -0
  56. package/evals/ab/personas/bindings/implementer.txt +43 -0
  57. package/evals/ab/personas/bindings/librarian.txt +40 -0
  58. package/evals/ab/personas/bindings/reviewer.txt +41 -0
  59. package/evals/ab/personas/corpus.json +69 -0
  60. package/evals/ab/personas/grader.mjs +171 -0
  61. package/evals/ab/personas/implementer.json +774 -0
  62. package/evals/ab/personas/implementer.md +22 -0
  63. package/evals/ab/personas/librarian.json +758 -0
  64. package/evals/ab/personas/librarian.md +22 -0
  65. package/evals/ab/personas/protocol/continuation.mjs.txt +284 -0
  66. package/evals/ab/personas/protocol/first-outcome.mjs.txt +227 -0
  67. package/evals/ab/personas/protocol/first-probe.mjs.txt +172 -0
  68. package/evals/ab/personas/protocol/publisher.mjs.txt +126 -0
  69. package/evals/ab/personas/protocol/second-probe.mjs.txt +193 -0
  70. package/evals/ab/personas/repairs/first-control-answer.txt +23 -0
  71. package/evals/ab/personas/repairs/grader-before-decode-repair.mjs.txt +143 -0
  72. package/evals/ab/personas/reviewer.json +758 -0
  73. package/evals/ab/personas/reviewer.md +22 -0
  74. package/evals/releases/0.4.0.json +154 -0
  75. package/evals/releases/0.4.0.md +69 -0
  76. package/evals/releases/0.4.1.json +154 -0
  77. package/evals/releases/0.4.1.md +69 -0
  78. package/package.json +6 -2
  79. package/packs/rituals/checkpoints/README.md +35 -0
  80. package/packs/rituals/checkpoints/pack.json +3 -2
  81. package/packs/tools/local-llm/README.md +46 -6
  82. package/packs/tools/local-llm/runner/local-llm.mjs +127 -13
  83. package/packs/tools/local-llm/skills/delegate-local/SKILL.md +26 -2
  84. package/spec/README.md +37 -4
  85. package/spec/migrations/0009-instruction-sections-on-read.mjs +60 -11
  86. package/spec/migrations/0011-persona-bindings-compiled.mjs +23 -0
  87. package/spec/migrations/README.md +6 -0
  88. package/spec/pack.schema.json +12 -3
  89. package/spec/slots.md +262 -117
  90. package/spec/workspace.schema.json +67 -11
@@ -29,10 +29,15 @@ token; `effort`, one of `low`, `medium`, `high`, `xhigh` or `max`; `omitClaudeMd
29
29
  unquoted, whether the role runs without the project's instruction files; and `cacheLifetime`, `5m` or
30
30
  `1h`. The effort levels and the name `omitClaudeMd` are adopted from Claude Code's vocabulary, the first
31
31
  host to express them. `effort` sets the host subagent's reasoning effort, and is not the thinking cap the
32
- `tools/local-llm` runner's `--effort` sends with each request it makes. `doctor` fails a
33
- malformed value and `compile` refuses one, and neither supplies a value the persona did not write. For a
34
- persona a composed pack ships, `compile` writes the declared fields into the frontmatter of the role's
35
- hand-written host binding, `agents/<name>.md` in the workspace's tree, and leaves every other line of
32
+ `tools/local-llm` runner's `--effort` sends with each request it makes. `doctor` fails malformed values
33
+ in composed pack personas; `compile` validates every persona source it compiles. Neither supplies a value
34
+ the persona did not write. `compile` writes declared fields from composed pack personas into the
35
+ frontmatter of the role's existing host binding: `agents/<name>.md` in a plugin tree and
36
+ `.claude/agents/<name>.md` in an ordinary project. Compiler and doctor share that selection; a malformed,
37
+ unreadable or escaping plugin marker is not treated as an ordinary project. When
38
+ the declared tree resolves to this compiler's own engine root, including a canonical alias, the same
39
+ pipeline also reads `core/personas/*.md` except this README. A foreign tree's matching files do not
40
+ participate. A core source's declared name must match its filename. The compiler leaves every other line of
36
41
  that file as its author wrote it; `--check` byte-compares the result, and a line inside the compiled
37
42
  block that `compile` did not write is refused rather than removed. One it cannot catch: a line added inside
38
43
  the block in exactly the spelling and order `compile` writes reads as compiled, and is dropped once the
@@ -41,19 +46,56 @@ field, `compile` owns every top-level key it could write, so a hand-written `exp
41
46
  even for a key other than `cacheTtl`. A field a host cannot express is
42
47
  named, with the persona and the host, in the degradation report `compile` prints. Claude Code takes all
43
48
  four on an agent (`cacheLifetime` as `experimental.cacheTtl`), and a vendored `AGENTS.md` takes none.
44
- **Claude Code loads `agents/` only from a plugin root**, and a repository that is not a plugin loads its
45
- agents from `.claude/agents/`, which `compile` does not write. So outside a plugin the compiled block is
46
- loaded by nothing, and the degradation report says so for each persona it applies to. Where the tree is
47
- a plugin root the report is silent, which is not proof of loading: a plugin's agents load only while it
48
- is installed and enabled, and `compile` cannot see that. _(Provenance:
49
+ `compile` writes only existing bindings; an absent adopter binding remains unbound and is never
50
+ created by compilation. A persona-only workspace can compile its declared fields without a gate
51
+ policy or guidance. Nonregular, escaping and invalid UTF-8 inputs are refused before writes.
52
+ Doctor checks the selected binding's name and declared tool grant, keeping an unread file distinct
53
+ from an absent one. Plugin packaging checks core and actually composed charter owners in both
54
+ directions, including personas declaring no context fields. File equality proves neither plugin
55
+ enablement nor that a running host honored a field. _(Provenance:
49
56
  proposal `0036`'s order of work, item 7, and proposal `0039`'s first two rules. The host's keys, values
50
57
  and agent locations were read in Claude Code 2.1.317's program text on 2026-11-03.)_
51
58
 
52
- A binding has one persona owner across composed packs, including an unbound persona or one declaring
59
+ This product binds both composed roles. Supervisor still requires a fresh invocation for a checkpoint.
60
+ Local-worker's host wrapper points to its existing loopback runner; loading that role does not itself
61
+ invoke a local model or prove local execution.
62
+
63
+ The three core sources explicitly declare `model: inherit`, `omitClaudeMd: false` and
64
+ `cacheLifetime: 5m`, leaving effort undeclared. These are product-role policy choices: inherit the
65
+ parent model, retain the instruction floor and request a five-minute cache lifetime. In Claude Code,
66
+ explicit `inherit` outranks the ordinary `CLAUDE_CODE_SUBAGENT_MODEL` default; an invocation's model
67
+ selection and `CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1` can override it. Cache lifetime remains subject to
68
+ the host's precedence rules. Compilation proves the committed bytes, with no claim about quality,
69
+ savings or live loading. _(Host precedence checked against the
70
+ [official subagent documentation](https://code.claude.com/docs/en/sub-agents) on 2026-11-09.)_
71
+
72
+ The acquired [implementer](../../evals/ab/personas/implementer.md),
73
+ [reviewer](../../evals/ab/personas/reviewer.md) and
74
+ [librarian](../../evals/ab/personas/librarian.md) comparisons each have three
75
+ frozen artifact cases, one attempt per arm, through native children on Sonnet 5.5
76
+ in Claude Code 2.1.321. Both arms pass all nine cases. Medium has a lower
77
+ cold-normalized cost index in this observation; observed cache costs differ,
78
+ and the reviewer arm's observed cost rises. These results support the retained
79
+ policy on that corpus and model, with no global medium default earned for other
80
+ inherited models. The [protocol](../../evals/ab/personas/README.md) discloses the
81
+ small sample, both probes, full parent/child usage and one retained-answer
82
+ decoder repair after the first outcome. The shipped offline checker regrades
83
+ the records and checks routing and source bytes.
84
+
85
+ A binding has one persona owner across core and composed pack sources, including an unbound persona or one declaring
53
86
  no fields; duplicate destinations are refused before any artifact is written. The binding must be a
54
87
  regular file whose real path stays in the real declared tree, including its parent directories.
55
88
  `omitClaudeMd` accepts only unquoted `true` or `false`, in both declarations and compiled blocks.
56
89
 
90
+ `upgrade` refreshes existing eligible bindings through the same compiler planner,
91
+ including normal host-cache pack discovery and its shadow refusals. It preserves
92
+ unrelated binding text and modes, creates no absent binding, and writes no gate
93
+ settings. Core sources still participate only in the installed engine's own
94
+ declared tree; an ordinary adopter receives the baked core agents by updating the
95
+ plugin, without installing a foreign core adapter. The command-level historical
96
+ v0.2.0 demonstration is in
97
+ [`../../cli/persona-upgrade.test.mjs`](../../cli/persona-upgrade.test.mjs).
98
+
57
99
  ## Status
58
100
 
59
101
  **Milestone 3 — contract, exemplars, and one host binding.** This README fixes the persona contract; the
@@ -2,6 +2,9 @@
2
2
  name: implementer
3
3
  description: The default working persona. Takes one task through the full loop — research → plan → implement → verify → learn — and hands back a verified change plus what it learned. Delegate a unit of implementation work to it.
4
4
  tools: [read, search, edit-code, run-verify, draft-memory, open-pr]
5
+ model: inherit
6
+ omitClaudeMd: false
7
+ cacheLifetime: 5m
5
8
  ---
6
9
 
7
10
  # Persona — Implementer
@@ -2,6 +2,9 @@
2
2
  name: librarian
3
3
  description: The persona that tends the curated layer — consolidating memory, regenerating the size-budgeted index, drafting rule-change proposals from incidents and PR reviews, and chasing stale rules toward retirement. It drafts and files; it never accepts. Delegate a memory/evolution housekeeping pass to it.
4
4
  tools: [read, search, read-history, draft-memory, draft-proposal, write-index, open-pr]
5
+ model: inherit
6
+ omitClaudeMd: false
7
+ cacheLifetime: 5m
5
8
  ---
6
9
 
7
10
  # Persona — Librarian
@@ -2,6 +2,9 @@
2
2
  name: reviewer
3
3
  description: The last-mile check on a change before it merges. Reads a proposed diff against the task's acceptance criteria and the definition of done, re-runs the verify recipe, and returns a verdict — it does not edit the code or merge. Delegate review of a completed change to it.
4
4
  tools: [read, search, run-verify, post-review]
5
+ model: inherit
6
+ omitClaudeMd: false
7
+ cacheLifetime: 5m
5
8
  ---
6
9
 
7
10
  # Persona — Reviewer
@@ -10,12 +10,16 @@
10
10
  > decisions and their rationale. When one is owed, and why the commit carries the rest:
11
11
  > `../operating/loop.md`.)_
12
12
  >
13
+ > Link the records that own measured figures and durable rules. Keep each open decision and its why.
14
+ > A declared token cap binds new handoffs; compress or move and link facts, never split or drop a why.
15
+ > The heading names the outcome; the filename already carries the date. See `../operating/context.md`.
16
+ >
13
17
  > **The commit a change lands in:** a subject that says what changed, in the present tense and under 72
14
18
  > characters; a blank line; a body of a few lines that says why, and what was rejected when that matters.
15
19
 
16
20
  ---
17
21
 
18
- # Handoff — {task / thread}
22
+ # {outcome / open task}
19
23
 
20
24
  **State.** {where things stand: what is done and committed, what is in progress and uncommitted.}
21
25
 
@@ -30,7 +34,7 @@
30
34
 
31
35
  _A filled one, for a session that stopped mid-change:_
32
36
 
33
- # Handoff — retry the flaky upload test
37
+ # Retry the flaky upload test
34
38
 
35
39
  **State.** The retry wrapper is written and its unit test passes; it is stashed, not committed, because
36
40
  the integration suite still fails once in about ten runs.
@@ -0,0 +1,111 @@
1
+ # Core persona routing comparisons
2
+
3
+ This protocol addresses [#520](https://github.com/sleepy-panda-srl/portulan/issues/520).
4
+ The frozen [corpus](corpus.json) has three artifact tasks per core role and one
5
+ attempt per arm. The [grader](grader.mjs) checks semantic behavior: bounded
6
+ execution and nonmutation for implementer code, executable counterexamples and
7
+ a clean control for reviewer findings, and preservation, escalation and human
8
+ authority for librarian drafts. These observations do not establish general
9
+ quality or a reliability rate.
10
+
11
+ A is the shipped role: inherited model, undeclared effort, instruction floor
12
+ retained and five-minute cache lifetime. B requests medium effort on the same
13
+ concrete inherited model through one native foreground persona child. The parent
14
+ runs at high effort; host request metadata must establish effective child effort.
15
+ The `--agent` main-session override is not this mechanism. Each parent and child
16
+ has a fresh context. Case order alternates A/B then B/A; an invalid invocation or
17
+ failed semantic control stops acquisition without resampling.
18
+
19
+ The observed concrete model is Sonnet 5.5 on Claude Code 2.1.321. A medium win on
20
+ this model and corpus does not establish medium effort for other inherited
21
+ models. The product retains `model: inherit` and undeclared effort; no global
22
+ lower-effort default is earned here.
23
+
24
+ ## Acquisition and accounting
25
+
26
+ Private originals retain the journal, CLI output, parent/child transcripts and
27
+ frozen source snapshots. Publication whitelists generic artifact answers,
28
+ numeric request metadata, normalized command arguments, timestamps and digests.
29
+ Answer presentation replaces only known acquisition and plugin-root prefixes
30
+ with `<acquisition>` and `<plugin>`; the record lists the affected answer and
31
+ retains both original and presented answer digests. Artifact contents and scores
32
+ are unchanged. Original answer wording otherwise remains.
33
+ Request identities and context identities are deterministically hashed; original
34
+ local paths, session identities and unrelated conversation content do not ship.
35
+ Public digests permit integrity checks; fidelity to private originals additionally
36
+ requires the independent acquisition review.
37
+
38
+ Acquisition fidelity **PASS**, signed `/root/checkpoint_520_open`, independent
39
+ read-only reviewer, 2026-11-10, for capture
40
+ `ff3688658bc20af6b78e834a5149ea6bd52bc88027b0340ec98cb52430c6d641`.
41
+ The reviewer independently checked all 80 requests (39 parent, 41 child), native
42
+ invocations, frozen sources, original answers, repair history and cost arithmetic.
43
+ The one disclosed citation normalization matches the deterministic transformation
44
+ and changes no JSON artifact or score. The checker and four capture/package tests
45
+ passed. This establishes retained-event fidelity; the sample, decoder repair,
46
+ reconstructed first-probe command and absence of billing evidence remain limits.
47
+
48
+ Two mechanism probes precede the eighteen quality children. The first used the
49
+ host's then-default Fable 5.2 and exceeded the configured one-dollar host-estimate
50
+ ceiling after a child ran. Its failed parent and child requests remain overhead;
51
+ it earns no quality result. Its command was reconstructed after execution from
52
+ the retained source, which was also snapshotted after execution. It is not a
53
+ contemporaneously recorded command. The second probe selected Sonnet 5.5 before
54
+ any quality outcome and demonstrated the native medium-effort mechanism. Quality
55
+ inference is limited to that model.
56
+
57
+ Every observed parent, child and probe request is counted once. The frozen price
58
+ vector is an index in uncached-input-token equivalents, not a price quotation or
59
+ subscription bill: uncached input 1, five-minute writes 1.25, one-hour writes 2,
60
+ unclassified writes 1.25, reads 0.1 and output 5. Registers separate observed
61
+ cost from a cold-normalized index. Normalization reprices all input in the first
62
+ request of each fresh parent and child context at 1.25, retaining subsequent
63
+ requests' observed classes and all output. Probe overhead is reported separately
64
+ from role comparisons. CLI USD values are host lifecycle estimates; they are not
65
+ added to these indexes.
66
+
67
+ ## Disclosed decoder repair
68
+
69
+ After the first quality outcome, acquisition stopped because the original
70
+ decoder rejected a correct function inside one JSON fence followed by prose.
71
+ The task requested a JSON artifact without forbidding surrounding prose; the
72
+ original decoder already allowed a whole-answer fence. The retained answer
73
+ passed the unchanged semantic execution checks.
74
+
75
+ The [original grader](repairs/grader-before-decode-repair.mjs.txt) and
76
+ [first answer](repairs/first-control-answer.txt) remain. A bounded decoder repair
77
+ accepts exactly one JSON fence with prose and rejects competing artifacts or
78
+ ambiguous fences. Semantic predicates, cases and pricing code stayed byte for
79
+ byte identical. The original false score is preserved alongside the repaired
80
+ true score. An independent checkpoint approved the exact decoder and continuation
81
+ instrument hashes before the remaining seventeen untouched calls. The first
82
+ child is never rerun. This is a post-outcome instrument repair, not an unchanged
83
+ preregistration.
84
+
85
+ ## Offline verification and delivery
86
+
87
+ The offline checker is `node cli/persona-routing.mjs --repo-root .`; it never
88
+ starts a host. It checks the immutable acquisition digest, all three role records,
89
+ semantic scores, generated registers, complete case/arm coverage, source and
90
+ binding bytes, effective effort, unique contexts/requests, frozen task bytes,
91
+ protocol snapshots, repair history and usage accounting. Exit 1 is a finding;
92
+ exit 2 is unavailable data or a failed read. The existing A/B recipe runs it.
93
+
94
+ The records and costs remain observations of source `01ca4887`; later bundle
95
+ changes are not new measurements. Current core charters must remain byte-identical
96
+ to that capture. A current plugin binding may change only its one nonempty,
97
+ single-line description scalar: every other byte, including tools, body and
98
+ context declarations, must match the historical binding. Malformed, duplicate,
99
+ missing or multiline descriptions refuse comparison. This permits the later
100
+ librarian description compression while preserving the acquired routing contract;
101
+ it establishes neither current whole-bundle costs nor equivalent automatic
102
+ delegation after description changes.
103
+
104
+ The npm payload carries the records, frozen protocol evidence, grader and offline
105
+ checker. Live acquisition and private normalization commands remain workshop
106
+ tools. A plugin update delivers the baked `agents/` files. The CLI's persona form
107
+ migration refreshes existing eligible bindings through the compiler planner:
108
+ core sources only in the installed engine's own tree, composed pack sources
109
+ through normal pack resolution. It creates no absent binding, installs no
110
+ foreign core adapter and changes no gate settings. The historical v0.2.0 suite
111
+ demonstrates actual check/write/check, idempotence, refusal and rollback.
@@ -0,0 +1,330 @@
1
+ {
2
+ "version": 1,
3
+ "phase": "complete",
4
+ "sourceCommit": "01ca48872fdceac9d7aa548ac12a5107173f2b31",
5
+ "host": "2.1.321 (Claude Code)",
6
+ "model": "claude-sonnet-5-5",
7
+ "seed": "portulan-m13-personas-20261110",
8
+ "prices": {
9
+ "uncached": 1,
10
+ "written5m": 1.25,
11
+ "written1h": 2,
12
+ "writtenUnknown": 1.25,
13
+ "read": 0.1,
14
+ "output": 5,
15
+ "coldFirstInput": 1.25
16
+ },
17
+ "routing": {
18
+ "model": "inherit",
19
+ "effort": null,
20
+ "omitClaudeMd": false,
21
+ "cacheLifetime": "5m"
22
+ },
23
+ "publication": {
24
+ "answerTransformation": "replace only known plugin-root and acquisition-root prefixes with <plugin> and <acquisition>",
25
+ "normalizedAnswers": [
26
+ "librarian-sealed-a"
27
+ ],
28
+ "note": "Original wording otherwise retained; original answers stay private with raw-answer digests. This presentation normalization changes no semantic artifact or score."
29
+ },
30
+ "qualityFrozenAt": "2026-11-10T07:29:01.199Z",
31
+ "continuationFrozenAt": "2026-11-10T07:49:23.195Z",
32
+ "order": [
33
+ "implementer-lower-bound-a",
34
+ "implementer-lower-bound-b",
35
+ "implementer-dedup-b",
36
+ "implementer-dedup-a",
37
+ "implementer-containment-a",
38
+ "implementer-containment-b",
39
+ "reviewer-verdict-b",
40
+ "reviewer-verdict-a",
41
+ "reviewer-clean-a",
42
+ "reviewer-clean-b",
43
+ "reviewer-boundaries-b",
44
+ "reviewer-boundaries-a",
45
+ "librarian-duplicate-a",
46
+ "librarian-duplicate-b",
47
+ "librarian-conflict-b",
48
+ "librarian-conflict-a",
49
+ "librarian-sealed-a",
50
+ "librarian-sealed-b"
51
+ ],
52
+ "taskSha256": {
53
+ "implementer-lower-bound": "4862de332848a8546671bbd33b6a2827d3bced336d65b92ed4aa8f02ce763290",
54
+ "implementer-dedup": "558e39b28c0f012f7fc5c0ceeec8898fd6fc77040305c587908b8795113afce8",
55
+ "implementer-containment": "2d991b5fc2fdb3e7d03dbebce8f9406d5ad1e55892d4dce1503a544b24cc525a",
56
+ "reviewer-verdict": "85e4e4f33f81550775e8b155906e2ecfe6c05661ce40da023e3723429a188102",
57
+ "reviewer-clean": "562e341017f1da94f7f8be4c6dd878db8c5ce1498596856c58f003c4256f28c2",
58
+ "reviewer-boundaries": "36d848b6d1d015225680efca9f459fb326b691906de006e429ce62f8f7bb793c",
59
+ "librarian-duplicate": "8332dd4efbcde4643088f07c07439d0abbdf7d703bf1dd4d332531196197512e",
60
+ "librarian-conflict": "4af2b7ce4790e069235825a0b5d64d61ec0a66f0e61294a313701d92d9eb6cca",
61
+ "librarian-sealed": "6408193ff1b6315658d34200116e15f7300e0a5c639fc36ae44391867a69828b"
62
+ },
63
+ "preflights": [
64
+ {
65
+ "key": "mechanism-medium",
66
+ "task": "mechanism",
67
+ "role": "implementer",
68
+ "effort": "medium",
69
+ "requestedModel": null,
70
+ "model": "claude-fable-5-2",
71
+ "parentEffort": "high",
72
+ "fresh": true,
73
+ "context": "context-bd202d2470debba47cf5529f97fd4759da5a81e041d200d112d8ade5c6dc2de0",
74
+ "childContext": "child-3e143bad7e549e19b35c2318b06a8121ad1695e3df8d41c473e09600cb9d2acf",
75
+ "state": "invalid",
76
+ "exit": 1,
77
+ "timedOut": false,
78
+ "started": "2026-11-10T07:15:36.623Z",
79
+ "ended": "2026-11-10T07:15:45.112Z",
80
+ "argv": [
81
+ "-p",
82
+ "This is a frozen evaluation. Invoke the Agent tool exactly once with these input values: {\"subagent_type\":\"portulan:implementer\",\"description\":\"Frozen persona artifact probe\",\"prompt\":\"Read <acquisition>/tasks/mechanism.json and follow its task exactly. This is an artifact proposal, not a completed repository change.\",\"run_in_background\":false,\"effort\":\"medium\"}. Do not supply a child model or change the effort. Wait for that foreground child to finish. Do not answer its task yourself or invoke another child. After completion reply only DONE.",
83
+ "--output-format",
84
+ "json",
85
+ "--effort",
86
+ "high",
87
+ "--plugin-dir",
88
+ "<plugin>",
89
+ "--tools",
90
+ "Agent,Read",
91
+ "--allowedTools",
92
+ "Agent(portulan:implementer),Read",
93
+ "--add-dir",
94
+ "<acquisition>/tasks",
95
+ "--max-budget-usd",
96
+ "1"
97
+ ],
98
+ "argvProvenance": "reconstructed-after-execution",
99
+ "instrumentSha256": "a02b6d2185b59e5b43a96a7cb3a5fcee7965c29a45b1533aa02c033369937f44",
100
+ "usage": {
101
+ "parent": [
102
+ {
103
+ "id": "request-832595efc5c05c77691a8e9c83ebd22210d0bf5aecccb43876f0e3860460dad8",
104
+ "model": "claude-fable-5-2",
105
+ "effort": "high",
106
+ "at": 1794294941008,
107
+ "uncached": 2,
108
+ "written5m": 83513,
109
+ "written1h": 0,
110
+ "writtenUnknown": 0,
111
+ "read": 0,
112
+ "output": 245
113
+ }
114
+ ],
115
+ "child": [
116
+ {
117
+ "id": "request-4e55082b4084a7622c2d5623a1b91d9bb0ba9e4a6e8445799b10ca7305295b36",
118
+ "model": "claude-fable-5-2",
119
+ "effort": "medium",
120
+ "at": 1794294942508,
121
+ "uncached": 2,
122
+ "written5m": 13333,
123
+ "written1h": 0,
124
+ "writtenUnknown": 0,
125
+ "read": 0,
126
+ "output": 314
127
+ },
128
+ {
129
+ "id": "request-9a157d22debc4d6232568c09309de1c0b38aeb1cfc73384bca3cbce633ad7eec",
130
+ "model": "claude-fable-5-2",
131
+ "effort": "medium",
132
+ "at": 1794294944421,
133
+ "uncached": 2,
134
+ "written5m": 5993,
135
+ "written1h": 0,
136
+ "writtenUnknown": 0,
137
+ "read": 13333,
138
+ "output": 11
139
+ }
140
+ ]
141
+ },
142
+ "raw": {
143
+ "parent": "218d6fdf034153ffafe1b6ac5a96854180ea6a4310a4876cd888bcd6ce067d64",
144
+ "child": "324d3c6e00ba0ac72ed03478bffbb6dbf65e8173490467b460f242eaca0fd3ec",
145
+ "result": "40affabe76d7e056ab7867a593410a74ecb2e3eac8e725fcdad5aecf45f2021f"
146
+ },
147
+ "hostEstimateUsd": 1.0539046,
148
+ "reason": "error_max_budget_usd",
149
+ "markerSeen": true,
150
+ "sourceSnapshotTiming": "after-execution",
151
+ "freshContextEvidence": "one parent transcript and one child transcript; no resume option"
152
+ },
153
+ {
154
+ "key": "mechanism-medium",
155
+ "task": "mechanism",
156
+ "role": "implementer",
157
+ "effort": "medium",
158
+ "requestedModel": "claude-sonnet-5-5",
159
+ "model": "claude-sonnet-5-5",
160
+ "parentEffort": "high",
161
+ "fresh": true,
162
+ "context": "context-9521e523e92aab3fb2a046a983432e56511424e7a91df2c4a5a76143e4f87dff",
163
+ "childContext": "child-847477035c4dfacc71140c7d805005629bc874cf015a83acf28bd62a2190be0f",
164
+ "state": "complete",
165
+ "exit": 0,
166
+ "timedOut": false,
167
+ "started": "2026-11-10T07:22:15.599Z",
168
+ "ended": "2026-11-10T07:22:29.819Z",
169
+ "argv": [
170
+ "-p",
171
+ "This is a frozen evaluation. Invoke the Agent tool exactly once with these input values: {\"subagent_type\":\"portulan:implementer\",\"description\":\"Frozen persona artifact probe\",\"prompt\":\"Read <acquisition>/tasks/mechanism.json and follow its task exactly. This is an artifact proposal, not a completed repository change.\",\"run_in_background\":false,\"effort\":\"medium\"}. Do not supply a child model or change the effort. Wait for that foreground child to finish. Do not answer its task yourself or invoke another child. After completion reply only DONE.",
172
+ "--output-format",
173
+ "json",
174
+ "--session-id",
175
+ "<parent-context>",
176
+ "--effort",
177
+ "high",
178
+ "--plugin-dir",
179
+ "<plugin>",
180
+ "--tools",
181
+ "Agent,Read",
182
+ "--allowedTools",
183
+ "Agent(portulan:implementer),Read",
184
+ "--add-dir",
185
+ "<acquisition>/tasks",
186
+ "--max-budget-usd",
187
+ "1",
188
+ "--model",
189
+ "claude-sonnet-5-5"
190
+ ],
191
+ "argvProvenance": "recorded-before-execution",
192
+ "instrumentSha256": "fbde0bff490748c02803a6f953505eaa057031285a39957573785cd14aa388d8",
193
+ "usage": {
194
+ "parent": [
195
+ {
196
+ "id": "request-8d5746971407ca792e9da0fb449c6028995eee2f8d7b2ddda1f4e6da61937613",
197
+ "model": "claude-sonnet-5-5",
198
+ "effort": "high",
199
+ "at": 1794295341109,
200
+ "uncached": 2,
201
+ "written5m": 82083,
202
+ "written1h": 0,
203
+ "writtenUnknown": 0,
204
+ "read": 0,
205
+ "output": 245
206
+ },
207
+ {
208
+ "id": "request-ac34361003d5e3e5e9d2ebe0ac70382e3e7aea7c418ec7c07c73ddc5813c5543",
209
+ "model": "claude-sonnet-5-5",
210
+ "effort": "high",
211
+ "at": 1794295346829,
212
+ "uncached": 2,
213
+ "written5m": 503,
214
+ "written1h": 0,
215
+ "writtenUnknown": 0,
216
+ "read": 82083,
217
+ "output": 5
218
+ }
219
+ ],
220
+ "child": [
221
+ {
222
+ "id": "request-9c5e95a551188dc248414fc894df567dadbd76c16bf02cfaa91a1c3cfd946425",
223
+ "model": "claude-sonnet-5-5",
224
+ "effort": "medium",
225
+ "at": 1794295342891,
226
+ "uncached": 2,
227
+ "written5m": 13337,
228
+ "written1h": 0,
229
+ "writtenUnknown": 0,
230
+ "read": 0,
231
+ "output": 314
232
+ },
233
+ {
234
+ "id": "request-f771db03c2ead365b17b2fcb5ef6f2e0d0d25b594161035e0a092fd115d2fc32",
235
+ "model": "claude-sonnet-5-5",
236
+ "effort": "medium",
237
+ "at": 1794295345372,
238
+ "uncached": 2,
239
+ "written5m": 5989,
240
+ "written1h": 0,
241
+ "writtenUnknown": 0,
242
+ "read": 13337,
243
+ "output": 11
244
+ }
245
+ ]
246
+ },
247
+ "raw": {
248
+ "result": "6b6faa6b1ee0157c9b931ab46e15e016df7f34b647bb34c1d7553ed6b2d81441",
249
+ "parent": "31fabf7e7f548051937823e01c49ec1b573d37d903a010eb72eecbdcde91b037",
250
+ "child": "f4af68b961cac7eacfec012332061b67b6ba2f34c2eeb7a9ffc9b43421b211a8"
251
+ },
252
+ "hostEstimateUsd": 0.27008800000000005,
253
+ "invocation": {
254
+ "type": "portulan:implementer",
255
+ "effort": "medium",
256
+ "promptSha256": "7bbcfe957dfaf278f89ae1cb9fb6902479eb1d8f53e131ce49d5f0aa74ff064d",
257
+ "model": null,
258
+ "background": false
259
+ },
260
+ "answer": "MECHANISM_OK",
261
+ "answerRawSha256": "72a7832e87334fc8c2dda2407f419a828f8fb30eda2eed583debfa49b4112c70",
262
+ "answerPresentationSha256": "72a7832e87334fc8c2dda2407f419a828f8fb30eda2eed583debfa49b4112c70",
263
+ "answerNormalized": false,
264
+ "transcriptDuplicates": {
265
+ "parent": 0,
266
+ "child": 2
267
+ },
268
+ "markerSeen": true
269
+ }
270
+ ],
271
+ "decodeRepair": {
272
+ "retainedKey": "implementer-lower-bound-a",
273
+ "approvedBy": "/root/checkpoint_520_open",
274
+ "approvalSha256": "9a8c8e99cfaec94ad350cac295d1f79dcca2396645c94578f575c9f69dab1b12",
275
+ "abortedJournalSha256": "6afb381b0e9d3eaefe2514e48d78295b01aec58ae2f878fdbb64c9fc667ad6ab",
276
+ "previousGrader": "9035deb344ea5a3ba5d31485836a5dda4d3dba6e06b20bfa78afb945ae1096b0",
277
+ "grader": "914d7744b73e9a79dd157038ed57c6f3034b2a05ce46fb4b5546a08b2e660978",
278
+ "observedOutcomes": 1,
279
+ "approval": "PASS",
280
+ "reruns": 0,
281
+ "semanticSuffixSha256": "3b8bde9accae1687d26b4621cafbadf7fb11e8ebd5dfd348ba3d15534f451146",
282
+ "explanation": "After one outcome, the original decoder rejected one JSON fence followed by prose. The same retained answer passes the revised decoder; all semantic predicates, cases and price code are byte-identical. The original false score remains. Independent approval covered exact decoder and continuation instrument hashes before the remaining seventeen calls."
283
+ },
284
+ "accounting": {
285
+ "calls": 20,
286
+ "parentContexts": 20,
287
+ "qualityChildren": 18,
288
+ "requests": 80,
289
+ "note": "Both probes, every parent and every child are included. Host USD values are lifecycle estimates, not subscription bills, and are not added to the declared-vector indexes."
290
+ },
291
+ "sources": {
292
+ "evals/ab/personas/corpus.json": "89554b37030657bd7167395e425461cb6f7acf5c223090c074ff054c7dac6b9b",
293
+ "evals/ab/personas/grader.mjs": "914d7744b73e9a79dd157038ed57c6f3034b2a05ce46fb4b5546a08b2e660978",
294
+ "core/personas/implementer.md": "bea6b78808fd6c390ebdfb53124d0b132e8a1454d78cecbabe04a632a0e2d45c",
295
+ "core/personas/reviewer.md": "6c364f370e61bc80a32697dc7d84eeb267ef3a2bbf48da16744356a90ce5078f",
296
+ "core/personas/librarian.md": "a79ef87153c2a5f52d36bd33b95fcdc2b0ed9bf79362a76bbf6a85459c094f46"
297
+ },
298
+ "bindings": {
299
+ "implementer": "3c3874f38defa6ea2bb42e45aa5a3b4267cc6794e1c7b11edc27440f861c0b97",
300
+ "reviewer": "436896a48ce036eeab69091fce7cee7482e8891efa2315da288378d9158f9a69",
301
+ "librarian": "7ad4e74c09482940444be0a1fe4de7eacc98e24aee145fdb6c25a162879053fc"
302
+ },
303
+ "instruments": {
304
+ "firstProbe": {
305
+ "sha256": "a02b6d2185b59e5b43a96a7cb3a5fcee7965c29a45b1533aa02c033369937f44",
306
+ "timing": "snapshotted-after-execution"
307
+ },
308
+ "secondProbe": {
309
+ "sha256": "fbde0bff490748c02803a6f953505eaa057031285a39957573785cd14aa388d8",
310
+ "timing": "frozen-before-execution"
311
+ },
312
+ "firstOutcome": {
313
+ "sha256": "2f0c0843c55ced112b8f5fc6872de6acb84f16319dcdd8edcf763bac4c37aa30",
314
+ "timing": "frozen-before-execution"
315
+ },
316
+ "continuation": {
317
+ "sha256": "34a45b79d5d3a762bbcd46222bdefe479cf031d1d0150665763b8de1c78981ab",
318
+ "timing": "approved-and-frozen-before-seventeen-untouched-cells"
319
+ },
320
+ "publisher": {
321
+ "sha256": "58ceb6aa7b361f627816fc92c1b7cdc755b3c473c5509b25c1a97c3c88a0d96c",
322
+ "timing": "after-acquisition; whitelisted normalization only"
323
+ }
324
+ },
325
+ "files": {
326
+ "implementer.json": "0b63097bec76852cccdd8edf3c7c9f20d83b9caae9536d1badb51a269003cdef",
327
+ "reviewer.json": "b9ea8b9d5b24ab33b67a1274b507b8416a482d349a9d64b4261b76ceac856774",
328
+ "librarian.json": "adf79f475a83dcc321dff1e4867d9af232052ffda6ffc92e5d2c8c75cf65a466"
329
+ }
330
+ }
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: implementer
3
+ description: Carries one task through the full loop — research, plan, implement, verify, learn — and hands back a verified change plus what it learned. Delegate a single unit of implementation work to it. It does not merge and it does not take gated actions.
4
+ tools: Read, Glob, Grep, Edit, Write, Bash
5
+ # compiled by `portulan compile` from core/personas/implementer.md; edit that file, then recompile
6
+ model: "inherit"
7
+ omitClaudeMd: false
8
+ experimental:
9
+ cacheTtl: 5m
10
+ ---
11
+
12
+ You are the **implementer** persona of the Portulan engine. Read
13
+ `${CLAUDE_PLUGIN_ROOT}/core/personas/implementer.md` for your charter and
14
+ `${CLAUDE_PLUGIN_ROOT}/core/operating/loop.md` for the loop you carry. This file binds that persona to
15
+ this host; the doctrine lives there, and where the two ever disagree, the persona wins.
16
+
17
+ Take **one task** from intent to a demonstrated change:
18
+
19
+ 1. **Research** before planning. Read the repository's workspace — its gate map, definition of done,
20
+ the repo card for this repository, and relevant memory — and never guess what you can check.
21
+ 2. **Plan** to a testable shape. If the acceptance criteria cannot be written as observable checks,
22
+ run the `clarify` skill rather than starting anyway.
23
+ 3. **Implement** at the altitude of the surrounding code. Writes are isolated: one branch, your own
24
+ files.
25
+ 4. **Verify** by climbing the hierarchy — it compiles, then tests pass, then the behaviour is
26
+ exercised. Run the workspace's verify recipe and read the output. Never report done on what you
27
+ could not walk a reviewer through line by line.
28
+ 5. **Learn**: write back what the task taught, as a draft. You draft memory and propose rule changes;
29
+ you never accept them. That gate is a human's.
30
+
31
+ **What you do not do.** You do not merge your own work, and you do not take an action the workspace's
32
+ gate map places in the Gated tier — merging, deleting a remote branch, publishing, changing settings,
33
+ spending money, or anything that speaks for the team beyond this repository. You prepare such an action
34
+ and hand it to the human. Which actions those are is the gate map's to say and not this file's, so read
35
+ it rather than this list. Where the line falls — whether pushing a working branch is Auto, say, or the
36
+ gate sits at the merge — is a property of the workspace you are standing in, not of this binding: these
37
+ files ship with the plugin into repositories whose gate maps this one has never seen.
38
+
39
+ **One honest limit of this binding.** The engine states your reach as capability classes; this host's
40
+ allow-list is coarser. `Bash` is a single grant covering both running a verify recipe and running
41
+ `gh pr merge`, so the tool list cannot express the Auto/Gated line by itself. The line is held by the
42
+ gate map you read in step 1 and by the repository's platform floor — branch protection and required
43
+ checks — not by this frontmatter. Treat the gate map as binding regardless of what this host permits.