instar 1.3.127 → 1.3.129
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/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh +36 -0
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +29 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +64 -5
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/PreferencesManager.d.ts +121 -0
- package/dist/core/PreferencesManager.d.ts.map +1 -0
- package/dist/core/PreferencesManager.js +223 -0
- package/dist/core/PreferencesManager.js.map +1 -0
- package/dist/core/installCodexHooks.d.ts +7 -0
- package/dist/core/installCodexHooks.d.ts.map +1 -1
- package/dist/core/installCodexHooks.js +30 -2
- package/dist/core/installCodexHooks.js.map +1 -1
- package/dist/core/types.d.ts +62 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +6 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +12 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +36 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +62 -62
- package/src/scaffold/templates.ts +6 -0
- package/upgrades/1.3.128.md +84 -0
- package/upgrades/1.3.129.md +55 -0
- package/upgrades/side-effects/codex-autonomous-loop-driver.md +91 -0
- package/upgrades/side-effects/correction-preference-learning-sentinel-slice1a.md +132 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
review-convergence: complete
|
|
3
|
+
approved: true
|
|
4
|
+
approved-by: justin (topic 13435, 2026-05-30 — "Yes, go ahead as long as we do it carefully and we have a clear plan to regress")
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Upgrade Guide — vNEXT
|
|
8
|
+
|
|
9
|
+
<!-- bump: patch -->
|
|
10
|
+
|
|
11
|
+
## What Changed — codex agents can now sustain a multi-turn autonomous run (ships DARK)
|
|
12
|
+
|
|
13
|
+
A `codex exec` session runs one turn then exits — there was no "keep going" Stop hook
|
|
14
|
+
like Claude has, so a codex agent (Codey) couldn't carry a long autonomous task. This is
|
|
15
|
+
the headline Claude/Codex parity gap.
|
|
16
|
+
|
|
17
|
+
The mechanism already existed end-to-end (codex fires Stop hooks and honors
|
|
18
|
+
`{decision:"block", reason}` — verified in the codex 0.133 binary); the only missing piece
|
|
19
|
+
was the wiring. `installCodexHooks` now registers the shared `autonomous-stop-hook.sh`
|
|
20
|
+
(with a `--codex` arg) as a SEPARATE codex Stop group — mirroring how Claude registers its
|
|
21
|
+
loop hook — and the hook self-gates on `autonomousSessions.codexLoopDriver.enabled`.
|
|
22
|
+
|
|
23
|
+
Ships **DARK**: the flag defaults false, so the standing codex hook exits immediately (no
|
|
24
|
+
behavior change for any codex session) until it is explicitly enabled. Claude's autonomous
|
|
25
|
+
mode is byte-for-byte unchanged (its loop hook is registered separately, with no `--codex`
|
|
26
|
+
arg).
|
|
27
|
+
|
|
28
|
+
## What to Tell Your User
|
|
29
|
+
|
|
30
|
+
Nothing changes yet — this ships turned off. It is the foundation that will let a codex
|
|
31
|
+
agent keep working through a long task on its own (the way a Claude agent already can),
|
|
32
|
+
once it is enabled and verified live. Rollback is instant: turn the flag back off.
|
|
33
|
+
|
|
34
|
+
## Summary of New Capabilities
|
|
35
|
+
|
|
36
|
+
| Capability | How to Use |
|
|
37
|
+
|-----------|-----------|
|
|
38
|
+
| Codex autonomous-loop driver | Set `autonomousSessions.codexLoopDriver.enabled: true` in `.instar/config.json` (default false / dark). Off → instant rollback, no redeploy. |
|
|
39
|
+
| Standing codex Stop group | `installCodexHooks` registers `autonomous-stop-hook.sh --codex` as its own Stop group; re-armed automatically on update. |
|
|
40
|
+
|
|
41
|
+
## Evidence
|
|
42
|
+
|
|
43
|
+
- Repro: a `codex exec` autonomous job stops after one turn — no `.codex/hooks.json` loop
|
|
44
|
+
hook (only the Claude path was wired). Prerequisites verified on disk: codex fires Stop
|
|
45
|
+
hooks (`config.toml [hooks.state]`); honors block+reason (0.133 binary `StopCommandOutputWire`).
|
|
46
|
+
- Before/after: before — codex Stop chain has only the review trio; after — a second Stop
|
|
47
|
+
group carries the loop driver, self-gated dark.
|
|
48
|
+
- Unit: `tests/unit/installCodexHooks.test.ts` — separate instar Stop group, idempotent
|
|
49
|
+
re-install (never stacks), user Stop group preserved.
|
|
50
|
+
- Unit: `tests/unit/autonomous-stop-hook-codex-gate.test.ts` — `--codex` + flag absent/false
|
|
51
|
+
→ approve (dark) even with an active job; flag true → block; no `--codex` (Claude) → blocks
|
|
52
|
+
regardless of the flag (Claude path unaffected). Both sides of the gate.
|
|
53
|
+
- `tsc --noEmit` clean; `npm run lint` clean.
|
|
54
|
+
- Spec: `docs/specs/codex-autonomous-loop-driver.md` (+ `.eli16.md`).
|
|
55
|
+
- Side-effects: `upgrades/side-effects/codex-autonomous-loop-driver.md`.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Side-Effects Review — Codex autonomous-loop driver
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `codex-autonomous-loop-driver`
|
|
4
|
+
**Date:** `2026-05-30`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** see below (required — lifecycle machinery)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Adds a codex registration of the shared autonomous-stop-hook so a `codex exec` session
|
|
11
|
+
sustains a multi-turn autonomous run (the codex analog of Claude's Stop-hook loop). A
|
|
12
|
+
SEPARATE codex Stop group (`autonomous-stop-hook.sh --codex`) is added in
|
|
13
|
+
`installCodexHooks`; the hook self-gates on `autonomousSessions.codexLoopDriver.enabled`
|
|
14
|
+
(default false → DARK). Claude's path is byte-for-byte unchanged.
|
|
15
|
+
|
|
16
|
+
## Decision-point inventory
|
|
17
|
+
|
|
18
|
+
1. `IS_CODEX` gate in the hook (— is this a codex-registered invocation?).
|
|
19
|
+
2. `codexLoopDriver.enabled` flag check (— should the codex loop actually run?).
|
|
20
|
+
3. `groupIsInstarOwned` (— is this Stop group instar-owned, to replace not duplicate?).
|
|
21
|
+
|
|
22
|
+
## 1. Over-block
|
|
23
|
+
Could it block a stop that SHOULD proceed? Only when the flag is ON, an autonomous job is
|
|
24
|
+
active for this session, AND tasks remain — which is exactly the intended block (continue
|
|
25
|
+
the run). With the flag OFF (default) it never blocks. The existing ownership/duration/
|
|
26
|
+
emergency/completion terminal checks (unchanged) still release the session.
|
|
27
|
+
|
|
28
|
+
## 2. Under-block
|
|
29
|
+
Could it fail to block when it SHOULD continue? When the flag is OFF, yes — by design
|
|
30
|
+
(dark). When ON, the only residual is the open binary question of whether codex runs the
|
|
31
|
+
second Stop group (Phase-5 / live verification gates this before enabling; fallback =
|
|
32
|
+
move into group 0). No silent data loss either way — at worst the codex run stops early,
|
|
33
|
+
same as today.
|
|
34
|
+
|
|
35
|
+
## 3. Level-of-abstraction fit
|
|
36
|
+
The driver lives where Claude's does (the autonomous skill hook) and is registered where
|
|
37
|
+
codex's other standing hooks are (`installCodexHooks`). The flag sits with the other
|
|
38
|
+
autonomous-mode settings (`autonomousSessions`). No new subsystem.
|
|
39
|
+
|
|
40
|
+
## 4. Signal vs authority compliance
|
|
41
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
42
|
+
The hook is an AUTHORITY surface by nature (a Stop hook returns block/approve — same as
|
|
43
|
+
Claude's existing loop hook and codex's existing stop-gate-router). It does not newly
|
|
44
|
+
elevate authority: it reuses the established Stop-hook contract. The dark flag means the
|
|
45
|
+
authority is dormant until explicitly enabled. No monitoring/signal component is converted
|
|
46
|
+
into a blocker.
|
|
47
|
+
|
|
48
|
+
## 5. Interactions
|
|
49
|
+
- **Review trio (stop-gate-router / response-review / claim-intercept / scope-coherence):**
|
|
50
|
+
the driver is the LAST hook in the SAME Stop group (slot stop:0:N). Within-group block
|
|
51
|
+
precedence vs the router is verified live before enabling; worst case the session still
|
|
52
|
+
continues via the router (never strands).
|
|
53
|
+
- **Claude autonomous mode:** independent registration (settings.json vs .codex/hooks.json);
|
|
54
|
+
`IS_CODEX=0` for Claude → unchanged.
|
|
55
|
+
- **armCodexHooks:** the new hook changes the hooks.json hash → re-arm on update (handled
|
|
56
|
+
by the existing migration). Because it rides group 0 (a group codex already trusts/arms),
|
|
57
|
+
it adds NO new arm slot — avoiding the recurring-arm-spawn side-effect a separate group
|
|
58
|
+
(stop:1:0) would have caused (caught by the second-pass review, then designed out).
|
|
59
|
+
|
|
60
|
+
## 6. External surfaces
|
|
61
|
+
None new. No HTTP route, no Telegram message, no external API. The hook talks only to the
|
|
62
|
+
local server's existing `/autonomous/evaluate-completion` (unchanged) when a completion
|
|
63
|
+
condition is set.
|
|
64
|
+
|
|
65
|
+
## 7. Rollback cost
|
|
66
|
+
Lowest tier. Set `autonomousSessions.codexLoopDriver.enabled: false` → the standing hook
|
|
67
|
+
exits immediately (instant, no redeploy, no session kill). Full PR revert is clean
|
|
68
|
+
(additive change; removing the Stop group + the `IS_CODEX` block restores prior behavior).
|
|
69
|
+
|
|
70
|
+
## Conclusion
|
|
71
|
+
Safe to ship DARK. The only non-trivial residual (does codex run a second Stop group) is
|
|
72
|
+
gated behind the default-off flag and resolved by live verification before enabling — per
|
|
73
|
+
Justin's "careful + clear plan to regress" condition.
|
|
74
|
+
|
|
75
|
+
## Second-pass review (if required)
|
|
76
|
+
|
|
77
|
+
**Reviewer:** independent second-pass agent (lifecycle machinery — required)
|
|
78
|
+
**Status:** DONE 2026-05-30 — **CONCUR on shipping DARK.** Verified PASS on: Claude path
|
|
79
|
+
unchanged, dark gate cannot leak (all config-read failure paths → disabled), `$0` anchor,
|
|
80
|
+
groupIsInstarOwned idempotency, migration parity (both halves land). The reviewer caught a
|
|
81
|
+
fleet-wide arm side-effect from the original separate-group design (a `stop:1:0` slot codex
|
|
82
|
+
may never trust → recurring codex-TUI arm spawns on every update, even dark). **Resolved**
|
|
83
|
+
by moving the driver into the existing Stop group (slot stop:0:N) — no new arm slot. The
|
|
84
|
+
remaining open item (within-group block precedence + that the loop actually re-prompts a
|
|
85
|
+
real codex run) is gated to live verification BEFORE the flag is enabled, per the spec's
|
|
86
|
+
Phase 5 — it is not a merge/dark-ship blocker.
|
|
87
|
+
|
|
88
|
+
## Evidence pointers
|
|
89
|
+
- Unit: `tests/unit/installCodexHooks.test.ts` (separate Stop group, idempotent, user-group preserved).
|
|
90
|
+
- Unit: `tests/unit/autonomous-stop-hook-codex-gate.test.ts` (dark default / disabled / enabled / Claude-unaffected — both sides of the gate).
|
|
91
|
+
- Spec: `docs/specs/codex-autonomous-loop-driver.md` (+ `.eli16.md`).
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Side-effects review — Correction & Preference Learning Sentinel (Slice 1a)
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/CORRECTION-PREFERENCE-LEARNING-SENTINEL-SPEC.md` (§3.6, §7,
|
|
4
|
+
§9, §10 Slice 1a)
|
|
5
|
+
**Change:** new `src/core/PreferencesManager.ts`; inline
|
|
6
|
+
`GET /preferences/session-context` in `src/server/routes.ts`;
|
|
7
|
+
`monitoring.correctionLearning` config block (`src/core/types.ts` +
|
|
8
|
+
`src/config/ConfigDefaults.ts`); `CapabilityIndex.ts` entry; session-start hook
|
|
9
|
+
patch + `migrateClaudeMd` backfill + shadow-capability marker in
|
|
10
|
+
`src/core/PostUpdateMigrator.ts`; `generateClaudeMd` capability section +
|
|
11
|
+
Registry-First row + proactive trigger in `src/scaffold/templates.ts`; 3-tier +
|
|
12
|
+
wiring tests.
|
|
13
|
+
**Class:** new read-surface feature, ships OFF, signal-only (never gates,
|
|
14
|
+
blocks, or rewrites a message).
|
|
15
|
+
|
|
16
|
+
## What changed
|
|
17
|
+
|
|
18
|
+
A structured on-disk preferences file (`.instar/preferences.json`), the single
|
|
19
|
+
atomic writer for it (`recordPreference()`), an HTTP read route serving the
|
|
20
|
+
session-start block, and a session-start hook that injects that block on every
|
|
21
|
+
boot. Modeled 1:1 on the proven ORG-INTENT precedent
|
|
22
|
+
(`GET /intent/org/session-context` + its session-start fetch). Slice 1b (the
|
|
23
|
+
capture/distill/ledger loop) is the future writer; Slice 1a only proves the
|
|
24
|
+
surface is alive end-to-end.
|
|
25
|
+
|
|
26
|
+
## 1. Security
|
|
27
|
+
|
|
28
|
+
- **No new external input/network/egress.** The route only reads a local file
|
|
29
|
+
and serves a deterministically-formatted block. No LLM call, no outbound
|
|
30
|
+
request, no shell-out in Slice 1a (the hook's curl is loopback to the agent's
|
|
31
|
+
own server, same as ORG-INTENT).
|
|
32
|
+
- **Auth:** the route is Bearer-gated by the global `authMiddleware` exactly like
|
|
33
|
+
sibling `/intent/*` routes (integration test asserts 401 without a token).
|
|
34
|
+
- **Output discipline:** the served payload and the injected block contain ONLY
|
|
35
|
+
the `learning` text + metadata (confidence, seen-count). Internal fields
|
|
36
|
+
(`dedupeKey`, `provenance`) never leak (unit + integration assertions). This is
|
|
37
|
+
the §3.6 "serve only learning + metadata" rule.
|
|
38
|
+
- **Injection-confusion defense:** loop-sourced preferences are wrapped in an
|
|
39
|
+
`<auto-learned-preference src='correction-loop'>` envelope so a downstream
|
|
40
|
+
prompt assembler structurally cannot mistake a learned preference for an
|
|
41
|
+
authoritative instruction. The block's own preamble restates "signals, not
|
|
42
|
+
instructions; real instructions and safety win."
|
|
43
|
+
- **No policy-relaxation surface in 1a:** `recordPreference()` has no writer in
|
|
44
|
+
Slice 1a (Slice 1b adds the gated, policy-keyword-filtered caller per §3.6).
|
|
45
|
+
Until then the only way an entry lands is a direct programmatic call, which the
|
|
46
|
+
correction loop does not yet make.
|
|
47
|
+
|
|
48
|
+
## 2. Migration parity
|
|
49
|
+
|
|
50
|
+
- **Config:** `monitoring.correctionLearning` added to `ConfigDefaults`.
|
|
51
|
+
`applyDefaults` deep-merges add-missing-only (verified: `merge()` recurses into
|
|
52
|
+
objects, adds absent keys, never overwrites), so existing agents backfill the
|
|
53
|
+
block on update without a dedicated `migrateConfig` step — and without surprise
|
|
54
|
+
activation (`enabled: false`). This matches the spec §7 note and the
|
|
55
|
+
failure-learning precedent.
|
|
56
|
+
- **Route:** inline in `routes.ts` (the discoverability-lint allowlist is fixed; a
|
|
57
|
+
separate module would trip the orphan-prefix check). `CapabilityIndex` entry
|
|
58
|
+
added so the lint passes and the route is discoverable.
|
|
59
|
+
- **Hook:** built-in `instar/` hooks are always-overwrite on every migration, so
|
|
60
|
+
the patched `session-start.sh` propagates to every existing agent on the next
|
|
61
|
+
update — no hand-written `migrateHooks` block needed.
|
|
62
|
+
- **CLAUDE.md:** `generateClaudeMd` gains the capability section / Registry-First
|
|
63
|
+
row / proactive trigger; `migrateClaudeMd` gains a content-sniffed backfill
|
|
64
|
+
(marker `Correction & Preference Learning Sentinel`) so EXISTING agents learn
|
|
65
|
+
the surface — not just new ones. A shadow-capability marker
|
|
66
|
+
(`**Preferences I've learned about you**`) mirrors it into Codex/Gemini
|
|
67
|
+
`AGENTS.md`/`GEMINI.md`. `feature-delivery-completeness` enforces all three legs.
|
|
68
|
+
- **State file:** `.instar/preferences.json` is created lazily on first write;
|
|
69
|
+
absent ≡ empty. No migration needed.
|
|
70
|
+
|
|
71
|
+
## 3. Performance
|
|
72
|
+
|
|
73
|
+
- The read route does one small synchronous file read + a deterministic
|
|
74
|
+
string-build bounded by `maxInjectedPreferencesBytes` (4000). No DB, no LLM, no
|
|
75
|
+
network. Cost is negligible and constant-ish.
|
|
76
|
+
- `recordPreference()` reads + rewrites the whole file atomically. The file is
|
|
77
|
+
bounded by distinct-preference cardinality (upsert by `dedupeKey`), not message
|
|
78
|
+
volume, so it stays tiny in practice. Each write is one temp-file + fsync +
|
|
79
|
+
rename.
|
|
80
|
+
- The session-start hook adds one loopback curl with `--max-time 4`; fail-open on
|
|
81
|
+
timeout, so a slow/absent server can never delay session start beyond that cap.
|
|
82
|
+
|
|
83
|
+
## 4. Observability
|
|
84
|
+
|
|
85
|
+
- The route is discoverable via `GET /capabilities` (CapabilityIndex entry,
|
|
86
|
+
`enabled` reflects the flag).
|
|
87
|
+
- `{ present, block, count }` makes the served state self-describing; `count`
|
|
88
|
+
exposes distinct-preference cardinality for debugging.
|
|
89
|
+
- No new log channel in 1a (the audit log `logs/correction-learning-audit.jsonl`
|
|
90
|
+
is a Slice 1b concern — the loop that produces routable decisions).
|
|
91
|
+
|
|
92
|
+
## 5. Rollback
|
|
93
|
+
|
|
94
|
+
- Flip `monitoring.correctionLearning.enabled` back to false (or remove the
|
|
95
|
+
block) → the route 503s and the hook injects nothing. Inert.
|
|
96
|
+
- `.instar/preferences.json` entries all carry `provenance: 'correction-loop'`,
|
|
97
|
+
enabling a one-shot bulk removal (a single jq-style filter) if a future loop
|
|
98
|
+
ever writes something unwanted. In 1a nothing writes, so the file stays absent.
|
|
99
|
+
- Code rollback = revert the commits; the absent-file ≡ empty contract means a
|
|
100
|
+
rolled-back agent with a stray file is still consistent (read tolerates and
|
|
101
|
+
ignores it; the route 503s when the flag is gone).
|
|
102
|
+
|
|
103
|
+
## 6. Multi-machine
|
|
104
|
+
|
|
105
|
+
- The file is per-agent-home local state (under `stateDir`), like ORG-INTENT.md
|
|
106
|
+
and the integrated-being ledger. On a multi-machine agent each machine reads
|
|
107
|
+
its own copy; the existing state-sync layer carries `.instar/` files between
|
|
108
|
+
machines the same way it carries ORG-INTENT.md — no new sync path introduced.
|
|
109
|
+
- The route is read-only and idempotent; no lease/fencing interaction. Slice 1a
|
|
110
|
+
has no writer competing across machines (that is a Slice 1b consideration when
|
|
111
|
+
the loop runs only on the awake machine).
|
|
112
|
+
|
|
113
|
+
## 7. Multi-user
|
|
114
|
+
|
|
115
|
+
- Slice 1a is a pure read/inject surface and does not itself attribute a
|
|
116
|
+
preference to a user — it serves whatever was recorded. The multi-user
|
|
117
|
+
primary-user gate (§3.6) lives in Slice 1b, where corrections are attributed
|
|
118
|
+
and `recordPreference()` is actually called. Until then no user-shaped data can
|
|
119
|
+
enter the file via this feature.
|
|
120
|
+
- The injected block is the same for every session on the agent (it is the
|
|
121
|
+
agent's learned-about-this-operator preferences), consistent with the
|
|
122
|
+
single-operator model the rest of the agent assumes.
|
|
123
|
+
|
|
124
|
+
## Tests
|
|
125
|
+
|
|
126
|
+
- Unit: `tests/unit/PreferencesManager.test.ts` (13),
|
|
127
|
+
`tests/unit/preferences-wiring-integrity.test.ts` (7).
|
|
128
|
+
- Integration: `tests/integration/preferences-routes.test.ts` (5).
|
|
129
|
+
- E2E: `tests/e2e/preferences-session-context-lifecycle.test.ts` (6).
|
|
130
|
+
- Lint: `tests/unit/capabilities-discoverability.test.ts` (100) green;
|
|
131
|
+
`tests/unit/feature-delivery-completeness.test.ts` green (parity + shadow
|
|
132
|
+
marker for the new section).
|