From 5a48b3d4ff8388a6c6f42cab12536cdeea124e67 Mon Sep 17 00:00:00 2001 From: Chris Sheldrick Date: Sat, 25 Jul 2026 00:16:10 -0400 Subject: [PATCH 1/2] Add one-shot Noet init reconciler --- .github/workflows/noet-init-once.yml | 79 ++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/workflows/noet-init-once.yml diff --git a/.github/workflows/noet-init-once.yml b/.github/workflows/noet-init-once.yml new file mode 100644 index 0000000..c46da53 --- /dev/null +++ b/.github/workflows/noet-init-once.yml @@ -0,0 +1,79 @@ +name: Rerun Noet init once + +on: + push: + branches: + - agent/rerun-noet-init-2026-07-25 + +permissions: + contents: write + +jobs: + noet-init: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + - name: Reconcile current Noet init + shell: bash + run: | + node <<'NODE' + const fs = require('node:fs'); + const path = require('node:path'); + const MARKER_BEGIN = ""; + const MARKER_END = ""; + const OPERATING_CONTENT = "# Noet Operating Contract\n\nThis repository uses Noet as an agent-operated continuity and judgment layer.\n\n## Operating loop\n\n**1. The first action for any repository task is:**\n```\nnoet apply --task \"\"\n```\nRun this **before** inspecting the repository, planning, or editing anything.\nConsume the output before choosing a direction. Running `apply` after\nimplementation has begun does not satisfy this step.\n\n**2. Record judgment in the same diff as the work that creates it:**\n- `noet record decision` — a project decision (with reason, current\n consequence, reversal condition, and action when met)\n- `noet record constraint` — a must or must-not\n- `noet record failure` — a prior failure that constrains future work\n- `noet record attention` — an unresolved obligation that must survive context\n replacement\n- `noet record continuity` — current goal, active direction, next action,\n and open questions\n\n**3. Never manually edit Noet-managed JSON stores under `.noet/`.**\nUse `noet record` commands. Hand-editing bypasses schema validation and will\ncause subsequent Noet invocations to fail closed.\n\n**4. Before claiming completion:**\nRun `noet verify run` (executes declared checks and records evidence), then\n`noet verify check` (falsifies the completion claim; must exit 0).\n\n**5. Preserve continuity and judgment updates** in the same diff as the work\nthat creates them. Confirmed-judgment records remain candidate until the human\nmerges the PR; merging confirms them. Provisional working state (continuity,\nattention) is adopted on merge but is not promoted to confirmed truth.\n\n**6. To run Noet commands,** use whichever of these is available:\n- An installed Noet CLI (for example, from the repository's local bin path\n via `npm exec -- noet`); or\n- An attached Noet checkout — the Noet source in a separate directory that\n you invoke by absolute path (see §7 below).\n\nIf neither is available, treat all `.noet/` state as read-only. Report that\nNoet cannot be safely operated. Do not hand-edit managed state.\n\n**7. Attached Noet checkout — explicit targeting required:**\nThe target repository (this project) and the Noet executable checkout are\ntwo distinct directories. When using an attached Noet checkout, always:\n\n- Invoke the Noet CLI by its **absolute path** — never by changing into the\n Noet checkout directory and running against ambient state.\n- Pass the target repository explicitly with **`--cwd `** on\n every command: `apply`, `record`, and `verify`.\n- Use the same `--cwd` for all commands in a session.\n- **Inspect the printed Noet target** before consuming applied judgment or\n continuing. If the target shows the Noet checkout directory instead of\n this repository, the output is irrelevant and must be discarded.\n\nExample (adapt paths; the Noet checkout and this repository will have\ndifferent names on your system):\n\n npx tsx /absolute/path/to/noet/src/cli.ts apply \\\n --cwd /absolute/path/to/target \\\n --task \"describe the current task\"\n\n npx tsx /absolute/path/to/noet/src/cli.ts record continuity \\\n --cwd /absolute/path/to/target \\\n --goal \"...\"\n\n npx tsx /absolute/path/to/noet/src/cli.ts verify run \\\n --cwd /absolute/path/to/target\n\n npx tsx /absolute/path/to/noet/src/cli.ts verify check \\\n --cwd /absolute/path/to/target\n\nThe human does not need to sequence Noet commands during ordinary work.\nThe agent operates Noet; the human reviews work via PR.\n"; + const CLAUDE_SECTION = "\nThe first action for any repository task is:\n noet apply --task \"\"\nRun this before inspecting the repository, planning, or editing. Consume the\noutput before choosing a direction. Running apply after implementation begins\ndoes not satisfy this step.\n\n@.noet/OPERATING.md\n"; + const AGENTS_SECTION = "\nThe first action for any repository task is:\n noet apply --task \"\"\nRun this before inspecting the repository, planning, or editing. Consume the\noutput before choosing a direction. Running apply after implementation begins\ndoes not satisfy this step.\n\nThis repository uses Noet. Read `.noet/OPERATING.md` for the full operating loop.\nDo not manually edit Noet-managed JSON files under `.noet/`.\n"; + const DEFAULTS = { + "PROJECT.md": "# PROJECT\n\n## Mission\n- Unnamed project\n\n## Boundaries\n-\n", + "STATE.md": "# STATE\n\n## Current goal\n- \n\n## Active context\n-\n## Open questions\n-\n", + "DECISIONS.md": "# DECISIONS\n\nRecord a row when a project judgment should travel with future work.\n\nAn empty Status cell means the decision currently governs. When project\njudgment changes, the old row is kept and its Status becomes\n`superseded by: ` (written by\n`noet record decision --supersede`); only the replacement renders as in\nforce.\n\n| Date | Decision | Reason | Current consequence | Reversal condition | Action when reversal condition is met | Status |\n| --- | --- | --- | --- | --- | --- | --- |\n", + "CONSTRAINTS.md": "# CONSTRAINTS\n\n## Musts\n-\n\n## Must-nots\n-\n", + "FAILURES.md": "# FAILURES\n\nRecord prior failures that constrain future work. Keep the description concrete\nenough for an agent to recognize when it applies.\n\n| Failure | Trigger | Symptoms | Mitigation | Status | Evidence |\n| --- | --- | --- | --- | --- | --- |\n", + "VERIFICATION.md": "# VERIFICATION\n\nDeclared checks an agent must prove before claiming completion.\n`noet verify run` executes commands listed here and records evidence;\n`noet verify check` falsifies a completion claim against them.\n\n## Commands\n- \n\nAppend ` — timeout: 300s` when a command legitimately needs more than\nNoet's 120-second default. Example: `- `npm run e2e` — timeout: 300s`\n\n## Artifacts\n- \n" + }; + function detectLineEnding(text) { return text.includes('\r\n') ? '\r\n' : '\n'; } + function toLineEnding(text, le) { const lf = text.replace(/\r\n/g, '\n'); return le === '\n' ? lf : lf.replace(/\n/g, '\r\n'); } + function reconcile(existing, section, label) { + if (existing === null) return section + '\n'; + const le = detectLineEnding(existing); + const adapted = toLineEnding(section, le); + const beginCount = (existing.match(//g) || []).length; + const endCount = (existing.match(//g) || []).length; + if (beginCount === 0 && endCount === 0) return existing.endsWith(le) ? existing + le + adapted + le : existing + le + le + adapted + le; + if (beginCount > 1 || endCount > 1) throw new Error(`${label}: duplicate noet managed-section markers (${beginCount} begin, ${endCount} end)`); + if (beginCount === 1 && endCount === 0) throw new Error(`${label}: noet:begin without noet:end`); + if (beginCount === 0 && endCount === 1) throw new Error(`${label}: noet:end without noet:begin`); + const begin = existing.indexOf(MARKER_BEGIN); + const end = existing.indexOf(MARKER_END); + if (end < begin) throw new Error(`${label}: noet:end appears before noet:begin`); + return existing.slice(0, begin) + adapted + existing.slice(end + MARKER_END.length); + } + function readOrNull(file) { return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null; } + const claude = reconcile(readOrNull('CLAUDE.md'), CLAUDE_SECTION, 'CLAUDE.md'); + const agents = reconcile(readOrNull('AGENTS.md'), AGENTS_SECTION, 'AGENTS.md'); + fs.mkdirSync('.noet', { recursive: true }); + for (const [name, content] of Object.entries(DEFAULTS)) { + const target = path.join('.noet', name); + if (!fs.existsSync(target)) fs.writeFileSync(target, content, 'utf8'); + } + if (readOrNull('.noet/OPERATING.md') !== OPERATING_CONTENT) fs.writeFileSync('.noet/OPERATING.md', OPERATING_CONTENT, 'utf8'); + if (readOrNull('CLAUDE.md') !== claude) fs.writeFileSync('CLAUDE.md', claude, 'utf8'); + if (readOrNull('AGENTS.md') !== agents) fs.writeFileSync('AGENTS.md', agents, 'utf8'); + fs.rmSync('.github/workflows/noet-init-once.yml'); + NODE + - name: Commit reconciled files + shell: bash + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + if git diff --cached --quiet; then + echo "No changes after reconciliation." + exit 0 + fi + git commit -m "Rerun Noet init with current operating contract" + git push origin "HEAD:${{ github.ref_name }}" From 8fdfed3fffb38b00129fc582a5de8d4046338d2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 04:16:21 +0000 Subject: [PATCH 2/2] Rerun Noet init with current operating contract --- .github/workflows/noet-init-once.yml | 79 ---------------------------- .noet/OPERATING.md | 78 +++++++++++++++++++++++++++ AGENTS.md | 11 ++++ CLAUDE.md | 10 ++++ 4 files changed, 99 insertions(+), 79 deletions(-) delete mode 100644 .github/workflows/noet-init-once.yml create mode 100644 .noet/OPERATING.md diff --git a/.github/workflows/noet-init-once.yml b/.github/workflows/noet-init-once.yml deleted file mode 100644 index c46da53..0000000 --- a/.github/workflows/noet-init-once.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Rerun Noet init once - -on: - push: - branches: - - agent/rerun-noet-init-2026-07-25 - -permissions: - contents: write - -jobs: - noet-init: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.ref_name }} - fetch-depth: 0 - - name: Reconcile current Noet init - shell: bash - run: | - node <<'NODE' - const fs = require('node:fs'); - const path = require('node:path'); - const MARKER_BEGIN = ""; - const MARKER_END = ""; - const OPERATING_CONTENT = "# Noet Operating Contract\n\nThis repository uses Noet as an agent-operated continuity and judgment layer.\n\n## Operating loop\n\n**1. The first action for any repository task is:**\n```\nnoet apply --task \"\"\n```\nRun this **before** inspecting the repository, planning, or editing anything.\nConsume the output before choosing a direction. Running `apply` after\nimplementation has begun does not satisfy this step.\n\n**2. Record judgment in the same diff as the work that creates it:**\n- `noet record decision` — a project decision (with reason, current\n consequence, reversal condition, and action when met)\n- `noet record constraint` — a must or must-not\n- `noet record failure` — a prior failure that constrains future work\n- `noet record attention` — an unresolved obligation that must survive context\n replacement\n- `noet record continuity` — current goal, active direction, next action,\n and open questions\n\n**3. Never manually edit Noet-managed JSON stores under `.noet/`.**\nUse `noet record` commands. Hand-editing bypasses schema validation and will\ncause subsequent Noet invocations to fail closed.\n\n**4. Before claiming completion:**\nRun `noet verify run` (executes declared checks and records evidence), then\n`noet verify check` (falsifies the completion claim; must exit 0).\n\n**5. Preserve continuity and judgment updates** in the same diff as the work\nthat creates them. Confirmed-judgment records remain candidate until the human\nmerges the PR; merging confirms them. Provisional working state (continuity,\nattention) is adopted on merge but is not promoted to confirmed truth.\n\n**6. To run Noet commands,** use whichever of these is available:\n- An installed Noet CLI (for example, from the repository's local bin path\n via `npm exec -- noet`); or\n- An attached Noet checkout — the Noet source in a separate directory that\n you invoke by absolute path (see §7 below).\n\nIf neither is available, treat all `.noet/` state as read-only. Report that\nNoet cannot be safely operated. Do not hand-edit managed state.\n\n**7. Attached Noet checkout — explicit targeting required:**\nThe target repository (this project) and the Noet executable checkout are\ntwo distinct directories. When using an attached Noet checkout, always:\n\n- Invoke the Noet CLI by its **absolute path** — never by changing into the\n Noet checkout directory and running against ambient state.\n- Pass the target repository explicitly with **`--cwd `** on\n every command: `apply`, `record`, and `verify`.\n- Use the same `--cwd` for all commands in a session.\n- **Inspect the printed Noet target** before consuming applied judgment or\n continuing. If the target shows the Noet checkout directory instead of\n this repository, the output is irrelevant and must be discarded.\n\nExample (adapt paths; the Noet checkout and this repository will have\ndifferent names on your system):\n\n npx tsx /absolute/path/to/noet/src/cli.ts apply \\\n --cwd /absolute/path/to/target \\\n --task \"describe the current task\"\n\n npx tsx /absolute/path/to/noet/src/cli.ts record continuity \\\n --cwd /absolute/path/to/target \\\n --goal \"...\"\n\n npx tsx /absolute/path/to/noet/src/cli.ts verify run \\\n --cwd /absolute/path/to/target\n\n npx tsx /absolute/path/to/noet/src/cli.ts verify check \\\n --cwd /absolute/path/to/target\n\nThe human does not need to sequence Noet commands during ordinary work.\nThe agent operates Noet; the human reviews work via PR.\n"; - const CLAUDE_SECTION = "\nThe first action for any repository task is:\n noet apply --task \"\"\nRun this before inspecting the repository, planning, or editing. Consume the\noutput before choosing a direction. Running apply after implementation begins\ndoes not satisfy this step.\n\n@.noet/OPERATING.md\n"; - const AGENTS_SECTION = "\nThe first action for any repository task is:\n noet apply --task \"\"\nRun this before inspecting the repository, planning, or editing. Consume the\noutput before choosing a direction. Running apply after implementation begins\ndoes not satisfy this step.\n\nThis repository uses Noet. Read `.noet/OPERATING.md` for the full operating loop.\nDo not manually edit Noet-managed JSON files under `.noet/`.\n"; - const DEFAULTS = { - "PROJECT.md": "# PROJECT\n\n## Mission\n- Unnamed project\n\n## Boundaries\n-\n", - "STATE.md": "# STATE\n\n## Current goal\n- \n\n## Active context\n-\n## Open questions\n-\n", - "DECISIONS.md": "# DECISIONS\n\nRecord a row when a project judgment should travel with future work.\n\nAn empty Status cell means the decision currently governs. When project\njudgment changes, the old row is kept and its Status becomes\n`superseded by: ` (written by\n`noet record decision --supersede`); only the replacement renders as in\nforce.\n\n| Date | Decision | Reason | Current consequence | Reversal condition | Action when reversal condition is met | Status |\n| --- | --- | --- | --- | --- | --- | --- |\n", - "CONSTRAINTS.md": "# CONSTRAINTS\n\n## Musts\n-\n\n## Must-nots\n-\n", - "FAILURES.md": "# FAILURES\n\nRecord prior failures that constrain future work. Keep the description concrete\nenough for an agent to recognize when it applies.\n\n| Failure | Trigger | Symptoms | Mitigation | Status | Evidence |\n| --- | --- | --- | --- | --- | --- |\n", - "VERIFICATION.md": "# VERIFICATION\n\nDeclared checks an agent must prove before claiming completion.\n`noet verify run` executes commands listed here and records evidence;\n`noet verify check` falsifies a completion claim against them.\n\n## Commands\n- \n\nAppend ` — timeout: 300s` when a command legitimately needs more than\nNoet's 120-second default. Example: `- `npm run e2e` — timeout: 300s`\n\n## Artifacts\n- \n" - }; - function detectLineEnding(text) { return text.includes('\r\n') ? '\r\n' : '\n'; } - function toLineEnding(text, le) { const lf = text.replace(/\r\n/g, '\n'); return le === '\n' ? lf : lf.replace(/\n/g, '\r\n'); } - function reconcile(existing, section, label) { - if (existing === null) return section + '\n'; - const le = detectLineEnding(existing); - const adapted = toLineEnding(section, le); - const beginCount = (existing.match(//g) || []).length; - const endCount = (existing.match(//g) || []).length; - if (beginCount === 0 && endCount === 0) return existing.endsWith(le) ? existing + le + adapted + le : existing + le + le + adapted + le; - if (beginCount > 1 || endCount > 1) throw new Error(`${label}: duplicate noet managed-section markers (${beginCount} begin, ${endCount} end)`); - if (beginCount === 1 && endCount === 0) throw new Error(`${label}: noet:begin without noet:end`); - if (beginCount === 0 && endCount === 1) throw new Error(`${label}: noet:end without noet:begin`); - const begin = existing.indexOf(MARKER_BEGIN); - const end = existing.indexOf(MARKER_END); - if (end < begin) throw new Error(`${label}: noet:end appears before noet:begin`); - return existing.slice(0, begin) + adapted + existing.slice(end + MARKER_END.length); - } - function readOrNull(file) { return fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null; } - const claude = reconcile(readOrNull('CLAUDE.md'), CLAUDE_SECTION, 'CLAUDE.md'); - const agents = reconcile(readOrNull('AGENTS.md'), AGENTS_SECTION, 'AGENTS.md'); - fs.mkdirSync('.noet', { recursive: true }); - for (const [name, content] of Object.entries(DEFAULTS)) { - const target = path.join('.noet', name); - if (!fs.existsSync(target)) fs.writeFileSync(target, content, 'utf8'); - } - if (readOrNull('.noet/OPERATING.md') !== OPERATING_CONTENT) fs.writeFileSync('.noet/OPERATING.md', OPERATING_CONTENT, 'utf8'); - if (readOrNull('CLAUDE.md') !== claude) fs.writeFileSync('CLAUDE.md', claude, 'utf8'); - if (readOrNull('AGENTS.md') !== agents) fs.writeFileSync('AGENTS.md', agents, 'utf8'); - fs.rmSync('.github/workflows/noet-init-once.yml'); - NODE - - name: Commit reconciled files - shell: bash - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - if git diff --cached --quiet; then - echo "No changes after reconciliation." - exit 0 - fi - git commit -m "Rerun Noet init with current operating contract" - git push origin "HEAD:${{ github.ref_name }}" diff --git a/.noet/OPERATING.md b/.noet/OPERATING.md new file mode 100644 index 0000000..a253c51 --- /dev/null +++ b/.noet/OPERATING.md @@ -0,0 +1,78 @@ +# Noet Operating Contract + +This repository uses Noet as an agent-operated continuity and judgment layer. + +## Operating loop + +**1. The first action for any repository task is:** +``` +noet apply --task "" +``` +Run this **before** inspecting the repository, planning, or editing anything. +Consume the output before choosing a direction. Running `apply` after +implementation has begun does not satisfy this step. + +**2. Record judgment in the same diff as the work that creates it:** +- `noet record decision` — a project decision (with reason, current + consequence, reversal condition, and action when met) +- `noet record constraint` — a must or must-not +- `noet record failure` — a prior failure that constrains future work +- `noet record attention` — an unresolved obligation that must survive context + replacement +- `noet record continuity` — current goal, active direction, next action, + and open questions + +**3. Never manually edit Noet-managed JSON stores under `.noet/`.** +Use `noet record` commands. Hand-editing bypasses schema validation and will +cause subsequent Noet invocations to fail closed. + +**4. Before claiming completion:** +Run `noet verify run` (executes declared checks and records evidence), then +`noet verify check` (falsifies the completion claim; must exit 0). + +**5. Preserve continuity and judgment updates** in the same diff as the work +that creates them. Confirmed-judgment records remain candidate until the human +merges the PR; merging confirms them. Provisional working state (continuity, +attention) is adopted on merge but is not promoted to confirmed truth. + +**6. To run Noet commands,** use whichever of these is available: +- An installed Noet CLI (for example, from the repository's local bin path + via `npm exec -- noet`); or +- An attached Noet checkout — the Noet source in a separate directory that + you invoke by absolute path (see §7 below). + +If neither is available, treat all `.noet/` state as read-only. Report that +Noet cannot be safely operated. Do not hand-edit managed state. + +**7. Attached Noet checkout — explicit targeting required:** +The target repository (this project) and the Noet executable checkout are +two distinct directories. When using an attached Noet checkout, always: + +- Invoke the Noet CLI by its **absolute path** — never by changing into the + Noet checkout directory and running against ambient state. +- Pass the target repository explicitly with **`--cwd `** on + every command: `apply`, `record`, and `verify`. +- Use the same `--cwd` for all commands in a session. +- **Inspect the printed Noet target** before consuming applied judgment or + continuing. If the target shows the Noet checkout directory instead of + this repository, the output is irrelevant and must be discarded. + +Example (adapt paths; the Noet checkout and this repository will have +different names on your system): + + npx tsx /absolute/path/to/noet/src/cli.ts apply \ + --cwd /absolute/path/to/target \ + --task "describe the current task" + + npx tsx /absolute/path/to/noet/src/cli.ts record continuity \ + --cwd /absolute/path/to/target \ + --goal "..." + + npx tsx /absolute/path/to/noet/src/cli.ts verify run \ + --cwd /absolute/path/to/target + + npx tsx /absolute/path/to/noet/src/cli.ts verify check \ + --cwd /absolute/path/to/target + +The human does not need to sequence Noet commands during ordinary work. +The agent operates Noet; the human reviews work via PR. diff --git a/AGENTS.md b/AGENTS.md index b4df54e..6151b81 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -65,3 +65,14 @@ Owns all selection/follow state (`selectedSystemId`, `selectedEmpireId`, `select - **Save compatibility**: `Simulation.importSave()` calls `upgradeState()` to patch missing fields from older saves. When adding new fields to `GalaxyState`, `Empire`, `StarSystem`, or `Fleet`, also add a `??=` default in `upgradeState()` and bump `SAVE_VERSION` if the shape change is breaking. - **Event IDs**: Empire and system event arrays (`historicalEventIds`, `recentEventIds`) store `Id` references into `state.events`. The global `eventLog` array is the ordered log of all event IDs. - **React / canvas split**: React components must not be in the canvas RAF loop. The canvas component must not set React state on every frame. + + +The first action for any repository task is: + noet apply --task "" +Run this before inspecting the repository, planning, or editing. Consume the +output before choosing a direction. Running apply after implementation begins +does not satisfy this step. + +This repository uses Noet. Read `.noet/OPERATING.md` for the full operating loop. +Do not manually edit Noet-managed JSON files under `.noet/`. + diff --git a/CLAUDE.md b/CLAUDE.md index 24cb995..3d464e5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -86,3 +86,13 @@ Owns all selection/follow state (`selectedSystemId`, `selectedEmpireId`, `select - **Save compatibility**: `Simulation.importSave()` calls `upgradeState()` to patch missing fields from older saves. When adding new fields to `GalaxyState`, `Empire`, `StarSystem`, or `Fleet`, also add a `??=` default in `upgradeState()` and bump `SAVE_VERSION` if the shape change is breaking. - **Event IDs**: Empire and system event arrays (`historicalEventIds`, `recentEventIds`) store `Id` references into `state.events`. The global `eventLog` array is the ordered log of all event IDs. - **React / canvas split**: React components must not be in the canvas RAF loop. The canvas component must not set React state on every frame. + + +The first action for any repository task is: + noet apply --task "" +Run this before inspecting the repository, planning, or editing. Consume the +output before choosing a direction. Running apply after implementation begins +does not satisfy this step. + +@.noet/OPERATING.md +