feat(graceful-handoff): remove hardcoded push window — push is now unconditional (v3.1.0)

The regime-wide push-window restriction (man–tor 08:00–17:00, fre 08:00–16:00)
was lifted permanently, so SKILL.md no longer gates the push on a weekday/time
window — it would otherwise park a push in the middle of working hours.

Two invariants are unchanged: push is Forgejo only (never GitHub), and push
stays user-triggered (the skill is disable-model-invocation: true). The pipeline
script had no window logic — only its header comment was corrected.

If a future repo needs a window again, reintroduce it as per-repo config, never
as a hardcoded default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BcNX2QdgmXyLd2Bt6Z25GU
This commit is contained in:
Kjell Tore Guttormsen 2026-06-24 11:00:10 +02:00
commit 192d4403eb
7 changed files with 26 additions and 20 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "graceful-handoff", "name": "graceful-handoff",
"version": "3.0.0", "version": "3.1.0",
"description": "One-command session handoff into the STATE.md continuity system. /graceful-handoff reaches a natural stopping point, overwrites the nearest STATE.md with a complete state-of-play (mandatory '👉 NESTE' block), and commits per remote policy (private → tracked, public mirror → local-only). Skill-only, deterministic STATE helper, no hooks.", "description": "One-command session handoff into the STATE.md continuity system. /graceful-handoff reaches a natural stopping point, overwrites the nearest STATE.md with a complete state-of-play (mandatory '👉 NESTE' block), and commits per remote policy (private → tracked, public mirror → local-only). Skill-only, deterministic STATE helper, no hooks.",
"author": { "author": {
"name": "Kjell Tore Guttormsen" "name": "Kjell Tore Guttormsen"

View file

@ -4,6 +4,12 @@ All notable changes to graceful-handoff are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [3.1.0] - 2026-06-24
### Changed
- **Removed the hardcoded push window — push is now unconditional, Forgejo only.** The regime-wide push-window restriction (mantor 08:0017:00, fre 08:0016:00) was lifted permanently, so SKILL.md no longer gates the push on a weekday/time window — it would otherwise park a push in the middle of working hours. The two other invariants are unchanged: **push is Forgejo only, never GitHub**, and **push stays user-triggered** (the skill is `disable-model-invocation: true` and never auto-pushes outside a user-invoked handoff). `handoff-pipeline.mjs` had no window logic — only its header comment was corrected. If a future repo needs a window again, reintroduce it as per-repo config, never as a hardcoded default.
## [3.0.0] - 2026-06-23 ## [3.0.0] - 2026-06-23
### BREAKING ### BREAKING

View file

@ -28,7 +28,7 @@ Bare sesjonsmodellen har konteksten til å fylle «👉 NESTE»-blokken meningsf
| `scripts/handoff-pipeline.mjs` | Slank deterministisk STATE-hjelper. `--plan` (resolver nærmeste STATE.md + klassifiser remote + git-fakta, read-only), `--commit` (stager KUN STATE.md når tracked + eksplisitte `--also`-stier; aldri `git add -A`), `--dry-run`. Returnerer JSON. Testbar uten LLM. | | `scripts/handoff-pipeline.mjs` | Slank deterministisk STATE-hjelper. `--plan` (resolver nærmeste STATE.md + klassifiser remote + git-fakta, read-only), `--commit` (stager KUN STATE.md når tracked + eksplisitte `--also`-stier; aldri `git add -A`), `--dry-run`. Returnerer JSON. Testbar uten LLM. |
Rituelet (SKILL.md): nå naturlig stoppunkt → `--plan` → skriv/overskriv STATE.md i fast format Rituelet (SKILL.md): nå naturlig stoppunkt → `--plan` → skriv/overskriv STATE.md i fast format
`--commit` → push kun i vindu → fast avslutningslinje. `--commit` → push (Forgejo) → fast avslutningslinje.
## STATE.md-format (ufravikelig) ## STATE.md-format (ufravikelig)
@ -70,9 +70,10 @@ remote-klassifisering, staging-disiplin (no-`git add -A`-regresjon), gitignored-
- v2.0.0 (2026-05-01): skill-arkitektur + JSON-pipeline + 3 hooks + auto-trigger (BREAKING) - v2.0.0 (2026-05-01): skill-arkitektur + JSON-pipeline + 3 hooks + auto-trigger (BREAKING)
- v2.1.0 (2026-05-01): modell-bevisst kontekstvindu (4-stegs resolution-kjede) - v2.1.0 (2026-05-01): modell-bevisst kontekstvindu (4-stegs resolution-kjede)
- v3.0.0 (2026-06-23): **STATE.md-integrasjon (BREAKING).** Fjernet NEXT-SESSION-artefakt + alle 3 hooks; invertert pipeline (modellen skriver STATE.md, skriptet assisterer); remote-aware tracked/local-only-policy; fjernet Sonnet-pin. - v3.0.0 (2026-06-23): **STATE.md-integrasjon (BREAKING).** Fjernet NEXT-SESSION-artefakt + alle 3 hooks; invertert pipeline (modellen skriver STATE.md, skriptet assisterer); remote-aware tracked/local-only-policy; fjernet Sonnet-pin.
- v3.1.0 (2026-06-24): fjernet hardkodet push-vindu — push er nå ubetinget (kun Forgejo, fortsatt user-triggered).
## Release (polyrepo — egen gated handling) ## Release (polyrepo — egen gated handling)
En versjonsbump er ikke fullført før: (1) `v3.0.0`-tag laget + pushet i denne repoen, OG (2) En versjonsbump er ikke fullført før: (1) `v3.0.0`-tag laget + pushet i denne repoen, OG (2)
katalogens `ref` bumpet til samme tag med `check-versions.mjs` grønn. Bruk katalogens `ref` bumpet til samme tag med `check-versions.mjs` grønn. Bruk
`../catalog/scripts/release-plugin.mjs graceful-handoff <versjon>` (atomisk). Krever push-vindu + operatør-go. `../catalog/scripts/release-plugin.mjs graceful-handoff <versjon>` (atomisk). Krever operatør-go.

View file

@ -6,7 +6,7 @@
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)* *AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
![Version](https://img.shields.io/badge/version-3.0.0-blue) ![Version](https://img.shields.io/badge/version-3.1.0-blue)
![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple) ![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple)
![Skill](https://img.shields.io/badge/skill-1-green) ![Skill](https://img.shields.io/badge/skill-1-green)
![Hooks](https://img.shields.io/badge/hooks-0-lightgrey) ![Hooks](https://img.shields.io/badge/hooks-0-lightgrey)
@ -47,7 +47,7 @@ Invoke it whenever you want to hand off. The session:
1. **Reaches the first natural stopping point** — finishes the current logical unit, leaves the code working. 1. **Reaches the first natural stopping point** — finishes the current logical unit, leaves the code working.
2. **Overwrites the nearest `STATE.md`** with a complete state-of-play in a fixed format, headed by a mandatory `👉 NESTE — START HER` block (where we are + the next concrete step + what to read). 2. **Overwrites the nearest `STATE.md`** with a complete state-of-play in a fixed format, headed by a mandatory `👉 NESTE — START HER` block (where we are + the next concrete step + what to read).
3. **Commits per remote policy** — staging *only* `STATE.md` (when tracked), never `git add -A`. 3. **Commits per remote policy** — staging *only* `STATE.md` (when tracked), never `git add -A`.
4. **Leaves push to you**, gated by your push window. 4. **Leaves push to you** — push to Forgejo, you-triggered (no window gate).
The skill is `disable-model-invocation: true`: the model cannot trigger a handoff on its own. Handoff is a deliberate, user-initiated moment. The skill is `disable-model-invocation: true`: the model cannot trigger a handoff on its own. Handoff is a deliberate, user-initiated moment.
@ -154,7 +154,7 @@ flowchart TB
SK -->|2. fetch facts| PLAN SK -->|2. fetch facts| PLAN
PLAN -->|JSON| SK PLAN -->|JSON| SK
SK -->|4. safe commit| COMMIT SK -->|4. safe commit| COMMIT
User -->|5. git push, in-window| Done((done)) User -->|5. git push (Forgejo)| Done((done))
``` ```
Two pieces, one responsibility each: the **skill** synthesizes `STATE.md` (only it has the context); the **helper** does the deterministic mechanics (path resolution, remote classification, safe staging). The helper has no LLM dependencies and runs under `node:test` in seconds. Two pieces, one responsibility each: the **skill** synthesizes `STATE.md` (only it has the context); the **helper** does the deterministic mechanics (path resolution, remote classification, safe staging). The helper has no LLM dependencies and runs under `node:test` in seconds.
@ -169,7 +169,7 @@ Two pieces, one responsibility each: the **skill** synthesizes `STATE.md` (only
2. **`--plan`** — fetch deterministic facts (resolved `STATE.md` path, remote class, git status, recent commits). 2. **`--plan`** — fetch deterministic facts (resolved `STATE.md` path, remote class, git status, recent commits).
3. **Write / overwrite `STATE.md`** in the mandatory format (title → `👉 NESTE` block → fixed sections → short history). Max ~60 lines. Overwrite, never append. 3. **Write / overwrite `STATE.md`** in the mandatory format (title → `👉 NESTE` block → fixed sections → short history). Max ~60 lines. Overwrite, never append.
4. **`--commit`** — stage only `STATE.md` (when tracked) plus any explicit `--also` paths the model judges belong to the unit. Never `git add -A`. 4. **`--commit`** — stage only `STATE.md` (when tracked) plus any explicit `--also` paths the model judges belong to the unit. Never `git add -A`.
5. **Push**check the window (`date '+%u %H:%M'`). In-window: push (Forgejo only, never GitHub). Out-of-window: park it and say so explicitly. 5. **Push**Forgejo only, never GitHub. Push is unconditional — no window gate.
6. **MEMORY.md check** — if it exceeds 200 lines, warn (don't auto-edit). 6. **MEMORY.md check** — if it exceeds 200 lines, warn (don't auto-edit).
7. **Fixed closing line** — STATE.md status (path) · next session's first action (= the `👉 NESTE` block) · commit/push status. 7. **Fixed closing line** — STATE.md status (path) · next session's first action (= the `👉 NESTE` block) · commit/push status.
@ -240,7 +240,7 @@ Enforced by tests, not convention:
- **Staging is explicit.** `--commit` stages *only* `STATE.md` (plus explicit `--also` paths). `git add -A` is never used — a regression test (`never stages unrelated dirty files`) enforces this. - **Staging is explicit.** `--commit` stages *only* `STATE.md` (plus explicit `--also` paths). `git add -A` is never used — a regression test (`never stages unrelated dirty files`) enforces this.
- **STATE.md never leaks to a public mirror.** On a public/`open/` remote `STATE.md` is gitignored and the helper refuses to commit it (`local-only-skipped`), verified by test. - **STATE.md never leaks to a public mirror.** On a public/`open/` remote `STATE.md` is gitignored and the helper refuses to commit it (`local-only-skipped`), verified by test.
- **Push is never automatic.** The helper never pushes; push stays user-triggered and window-gated. - **Push is never automatic.** The helper never pushes; push stays user-triggered (no window gate); never automatic.
- **Pre-commit hooks are respected.** The helper never uses `--no-verify`. - **Pre-commit hooks are respected.** The helper never uses `--no-verify`.
- **No network calls.** No WebSearch, no Agent delegation, no MCP — fully local. - **No network calls.** No WebSearch, no Agent delegation, no MCP — fully local.
- **Bash sub-scoped.** Skill `allowed-tools` enumerates `Bash(git:*) Bash(node:*) Bash(date:*)`. - **Bash sub-scoped.** Skill `allowed-tools` enumerates `Bash(git:*) Bash(node:*) Bash(date:*)`.

View file

@ -12,7 +12,7 @@
// STATE.md. // STATE.md.
// --commit : stage STATE.md (ONLY if it is NOT gitignored) plus any // --commit : stage STATE.md (ONLY if it is NOT gitignored) plus any
// explicit --also paths, then commit. NEVER `git add -A`. // explicit --also paths, then commit. NEVER `git add -A`.
// Never pushes (push stays window-gated + user-triggered). // Never pushes (push stays user-triggered — no window gate).
// --dry-run : never writes, never touches git. // --dry-run : never writes, never touches git.
// //
// Why STATE.md must never be auto-committed on a public mirror: a repo whose only // Why STATE.md must never be auto-committed on a public mirror: a repo whose only

View file

@ -67,7 +67,7 @@ _Current state-of-play. Overskrives (ikke append) ved sesjonsslutt. Historikk
## <Oppdrag & kjøremodus> ← fast/uforanderlig: hva er målet, hvordan jobbes det ## <Oppdrag & kjøremodus> ← fast/uforanderlig: hva er målet, hvordan jobbes det
## <Gotchas / ufravikelige regler> ← det neste sesjon MÅ vite for ikke å trå feil ## <Gotchas / ufravikelige regler> ← det neste sesjon MÅ vite for ikke å trå feil
## <Push-status> ← hva er pushet vs parkert, og push-vindu-regel ## <Push-status> ← hva er pushet vs parkert (push er fritt — ingen vindu-regel)
## <Repo & env> ← branch, remote-klasse, tester, sentrale tall ## <Repo & env> ← branch, remote-klasse, tester, sentrale tall
## <Sesjonssekvens / historikk> ← KORT; det meste hører i git ## <Sesjonssekvens / historikk> ← KORT; det meste hører i git
``` ```
@ -92,14 +92,13 @@ node ${CLAUDE_PLUGIN_ROOT}/scripts/handoff-pipeline.mjs --commit [--also <relate
ev. kode-endringer (via `--also`) og sier fra at STATE er local-only. ev. kode-endringer (via `--also`) og sier fra at STATE er local-only.
- Pre-commit hooks respekteres — aldri `--no-verify`. - Pre-commit hooks respekteres — aldri `--no-verify`.
### 5. Push — vindu-gated, aldri automatisk ### 5. Push (Forgejo, aldri automatisk utenfor handoff)
```bash Push er fritt — ingen ukedag/tidspunkt-gate. Etter `--commit`:
date '+%u %H:%M' # ukedag 1-7 + tid, norsk lokaltid - `git push origin <branch>`**kun Forgejo, ALDRI GitHub**.
``` - Hvis et repo har gitignored STATE.md (offentlig/`open/`-remote) committes/pushes kun
Sperret vindu: **mantor 08:0017:00** og **fre 08:0016:00**. Ellers fritt. ev. kode (`--also`-stier); STATE selv er local-only.
- I vindu: `git push origin <branch>` (kun Forgejo, ALDRI GitHub). - Skillen pusher kun innenfor en bruker-invokert handoff (den er
- Utenfor vindu: IKKE push. Hold commiten lokalt og si eksplisitt at pushen er parkert `disable-model-invocation: true`) — aldri spontant.
til neste vindu åpner.
### 6. MEMORY.md-sjekk (lett) ### 6. MEMORY.md-sjekk (lett)
Hvis auto-memory `MEMORY.md` finnes og er > 200 linjer: varsle bruker (flytt detalj til Hvis auto-memory `MEMORY.md` finnes og er > 200 linjer: varsle bruker (flytt detalj til

View file

@ -10,9 +10,9 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const MANIFEST = join(__dirname, '..', '.claude-plugin', 'plugin.json'); const MANIFEST = join(__dirname, '..', '.claude-plugin', 'plugin.json');
const CHANGELOG = join(__dirname, '..', 'CHANGELOG.md'); const CHANGELOG = join(__dirname, '..', 'CHANGELOG.md');
test('plugin.json version is 3.0.0', () => { test('plugin.json version is 3.1.0', () => {
const m = JSON.parse(readFileSync(MANIFEST, 'utf-8')); const m = JSON.parse(readFileSync(MANIFEST, 'utf-8'));
assert.equal(m.version, '3.0.0'); assert.equal(m.version, '3.1.0');
}); });
test('plugin.json description mentions STATE.md', () => { test('plugin.json description mentions STATE.md', () => {