Skip to content

About

Session warm-resume + handoff journal for AI coding agents - journals every step so an interrupted session resumes instead of rebuilding. Claude Code (validated) + 6 works-with ports (Antigravity, Gemini CLI, Copilot CLI, Devin CLI, Kiro, Augment). Reduces limit-hit damage; does not prevent it.

Topics

Resources

Code of conduct

Contributing

Security policy

Accessibility

Stars

1 star

Watchers

0 watching

Forks

🔥 CoalHearth

A hearth keeps the home warm and banks the embers so the next day's fire lights fast. This one banks a Claude Code session's state so an interrupted session resumes from a handoff instead of a manual rebuild.

A session warm-resume engine. A hook journals your session's state every step; if the next session finds the prior one was interrupted, it injects a markdown recovery block so you continue where you left off.

version license status

Claude Code: validated Antigravity: validated (plugin, headless) Gemini CLI: works with Copilot CLI: works with Devin CLI: works with Kiro: works with Augment: works with

Changelog · Security · Privacy · Releases

Docs: thecolliery.gitbook.io/thecolliery-docs/tools/coalhearth (publishing soon)

Part of TheColliery — siblings: CoalMine (quality canaries) · CoalTipple (model/effort routing) · CoalBoard (consensus board) · CoalFace (fan-out discipline) · CoalWash (memory defrag) · CoalLedger (docs health) · CoalGob (OS-trash delete guard, PUBLIC BETA v0.1.0-beta.1).


🔥 What it is

A session limit-hit or a crash loses in-flight work — the plan, the checklist, the list of files you were mid-edit on. CoalHearth reduces that loss:

  • The recovery core. A PostToolUse hook builds a best-effort snapshot of the session (goal + checklist from task.md, constraints from AGENTS.md, modified files accumulated from the file-editing tool calls the hook observes — no git spawn, no child processes) and journals it atomically every step to session_handoff.json.
  • Warm-resume on boot. On the next session's SessionStart, if the prior session's journal is still marked in_progress, CoalHearth injects a markdown recovery block — the goal, the checklist, the files it was touching, the planned next steps — so you resume from context instead of reconstructing it by hand.
  • Subagent-death visibility. A spawned subagent's tool call resolving (success or failure) is now captured with a status + a short outcome snippet from its own report — the "7 of 11 checks done" a revive-or-defer decision actually needs, not just a name. On Claude Code, an unsurfaced resolution also nudges on your very next prompt — seconds to minutes away, not a session restart.

Important

The recovery block never asks you to blind-trust it — it always tells the agent to verify against git status / git diff first, because the journal may be stale or half-applied.

That recovery core is the value.

🛡️ What it does (and does NOT) guarantee

CoalHearth reduces the damage of a session interruption — it does not prevent one, and it guarantees nothing:

  • The recovery journal is a best-effort snapshot, not a guarantee it's still accurate — code may have moved since the last save, which is exactly why the recovery block tells the agent to verify against git.
  • Work done by fanned-out workers that die on a limit is still unrecoverable in content — a dead subagent journals nothing of its own. What changed (issue #13): if the subagent's tool call itself RESOLVED (even with a failure status), the parent's journal now records that outcome + a short self-reported snippet — enough to price a revive-or-defer decision. A subagent whose tool call never resolves at all (a true mid-dispatch death) is still invisible until the next SessionStart.
  • Claude Code keeps its own session transcript, but retention is version-dependent, not the guaranteed 30 days its docs suggest — a transcript can be garbage-collected early, before you --resume it. CoalHearth's journal is a separate, local net that doesn't depend on it, and the recovery block flags a transcript that's already gone.

Honest sell: less lost work on an interruption — not a limit-proof session.

🪝 The hooks

All are Phoenix-13 hooks — fail-silent (any error is swallowed, exit 0, never crashes the host), zero-dependency (Node builtins only), no network, no child processes, and they emit only their one sanctioned channel.

  • SessionStart → resume (bin/session-start.js): reads the journal (bounded to 4 MiB; the journal this tool writes stays under that bound: past about 4 MiB the writer drops the oldest recorded paths, counts them, and the recovery block says how many earlier paths are not listed. A journal over the bound that this tool did not write, or one that is a link leaving the output directory, is not read, and the next recorded step replaces it with a fresh one), and if the prior session was interrupted, prints the recovery block on the sanctioned SessionStart context-injection channel, then marks the journal resumed so it isn't re-injected every boot. When a periodic self-update check is due (see update.*), it also prints a one-line /coalhearth:update nudge on the same channel — the hook only schedules via a local throttle stamp; the online check is the agent's, consent-gated. A headless/cron start is safe by construction — the hook only prints, it never asks anything.
  • PostToolUse → journal (bin/post-tool-use.js): builds the state snapshot and saves it atomically under a per-workspace lock (so two concurrent sessions can't lose each other's journal). Journal-only — it emits nothing.
  • UserPromptSubmit → subagent-death nudge (bin/user-prompt-submit.js, Claude Code only — issue #13): the common case is one cheap journal read and nothing else. When a spawned subagent's tool call has RESOLVED since the last time this fired, and its status/outcome hasn't been shown yet, it prints one nudge on the sanctioned UserPromptSubmit context-injection channel — description, status, and the self-reported outcome snippet — then marks it shown so the same resolution never repeats. This surfaces on your very next prompt in the SAME session, instead of waiting for a SessionStart that may be hours away. Every status is stated with a caveat: it's self-reported by the subagent and has been observed wrong.

On every other platform the resume + journal jobs run through thin adapters — bin/ag-pre-invocation.js (resume) and bin/ag-post-tool-use.js (journal) — over one shared core (lib/journal-step.js for the journal, lib/resume-engine.js for the recovery block); the Claude Code journal hook is itself a thin adapter over that core, behavior identical. A trailing argument in each platform's config picks the emit shape (Antigravity flat JSON · Gemini nested hookSpecificOutput · plain Claude-Code stdout for the CC-shaped file-copy platforms); the parsing/journal logic never forks. The subagent status/outcome capture and the enriched resume-block rendering reach every platform via those shared cores — only the mid-session UserPromptSubmit nudge itself is Claude-Code-specific this release (no other platform's config wires an equivalent per-prompt event to it; a decoupled PreInvocation variant for Antigravity is a named, unbuilt follow-up).

🚀 Install

CoalHearth is two Phoenix-13 hooks (resume + journal), so it installs wherever a platform runs hooks and has both a session-start-class event and a per-tool event — the pair the product needs (journal without resume is write-only; resume without journal has nothing to read). All platforms run the same shared core through thin adapter entry points.

Compat matrix (tier honesty: validated = a real end-to-end run has been done on that platform · works with = built + hermetically tested against the platform's primary docs, 2026-07-15 fetch — not yet proven there; a claim only becomes validated after a real run):

Platform Tier Events (resume + journal) Wiring
Claude Code validated SessionStart + PostToolUse + UserPromptSubmit ² plugin (automatic)
Antigravity 2.0 validated (plugin path, headless agy -p; the global and project hooks.json paths stay unproven) first PreInvocation (once-per-session marker) + PostToolUse native plugin: plugin.json + hooks.json (or platform-configs/hooks.json for a global or project file)
Gemini CLI ¹ works with SessionStart + AfterTool platform-configs/hooks/gemini-settings-hooks.json
GitHub Copilot CLI works with sessionStart + postToolUse platform-configs/hooks/copilot-cli-hooks.json
Devin CLI works with SessionStart + PostToolUse platform-configs/hooks/devin-cli-hooks.json
Kiro works with agentSpawn + postToolUse platform-configs/hooks/kiro-agent-hooks.json
Augment Code works with SessionStart + PostToolUse platform-configs/hooks/augment-settings-hooks.json
Junie not supported SessionStart is its ONLY event — no per-tool event means no journal, so resume would have nothing to read —
Devin Desktop (Cascade Hooks) not supported its snake_case vocabulary (pre/post_write_code, post_cascade_response, …) has no session-start-class event — no resume anchor; a separate surface from Devin CLI —

¹ Gemini CLI audience caveat: individual/AI-Pro/Ultra tiers were cut off 2026-06-18 — it is a business-tier product (Standard/Enterprise) now. ² UserPromptSubmit (the subagent-death nudge, issue #13) is Claude-Code-only this release — see "The hooks" above.

Claude Code — validated

One command (this also wires the hooks):

claude plugin marketplace add TheColliery/CoalHearth
claude plugin install coalhearth@coalhearth

That's it — the hooks activate on your next session. No API keys, no network, no configuration required to start.

Antigravity — validated on the plugin path, headless (agy 1.3.1, 2026-10-08); the global and project hooks.json paths stay unproven

Observed 2026-10-08 (plugin path): on agy 1.3.1, headless agy -p, Windows, a copy of the plugin folder at <workspace>/.agents/plugins/coalhearth fired BOTH adapters: the journal was written under Antigravity's own conversation id, the resume block reached the model (it quoted the planted goal and next step), while a copy of the repository root and a plugins.json path entry were each shown to fire the journal (PostToolUse) leg only; resume delivery was observed in the workspace-folder copy. This is the first observed fire of this room's own hook pair, and it is what validated asks for, for THIS path only. Limits of the evidence: the interactive IDE was not exercised; a Windows junction to the folder was NOT discovered (copy it; a symbolic link was not tried); agy plugin list does not list a folder-discovered plugin; ask_question is auto-skipped under -p; agy plugin install https://github.com/TheColliery/CoalHearth.git was run once from a folder with no git (2026-10-08): exit 0, agy plugin list then listed coalhearth (components: commands and hooks), the whole repository was cloned to ~/.gemini/config/plugins/coalhearth/ and the two commands were imported as skills; whether the hooks fire from that installed folder was NOT measured. The older tests below used a global or project hooks.json, never a plugin, and stay recorded as negative with their dates.

Documented: Antigravity 2.0 ships a real hook engine (hooks.json; antigravity.google/docs/hooks, corroborated against the docs 2026-07-13), which reopens CoalHearth to AG — the old "Claude Code only, because no other agent runs hooks" premise no longer holds. The port is built and hermetically tested against that documented spec.

What "empirically confirmed 2026-07-12" actually established: that date's pilot fired a live Stop hook on AG — proving the engine itself can fire — but in a sibling plugin (CoalMine), on a different event. CoalHearth's own PreInvocation/PostToolUse pair was never part of that fire; it was built and tested against the spec the pilot confirmed, never observed firing itself. This section previously implied otherwise by putting the date next to CoalHearth's own claim — corrected here.

Tested 2026-08-04, observed: both hook locations this doc names below (global ~/.gemini/config/hooks.json and per-project <workspace>/.agents/hooks.json) were installed; a fresh AG session ran a real tool call (list_dir, confirmed in AG's own transcript log); a plain control command written the identical way FIRED (ruling out a broken command shape). Neither CoalHearth's PreInvocation hook nor its PostToolUse hook (tested with both a wildcard * matcher and the exact tool-name matcher) produced a single log line.

Reproduced twice since, against the same underlying hook engine (2026-08-22 and 2026-08-23): two further probes — run headless via agy -p, on two separate days, with two different tool-call shapes — fired zero hooks against a pre-existing, schema-valid hooks.json at the shared cross-tool location (~/.gemini/config/hooks.json), with real tool execution confirmed in each run. Those probes are not CoalHearth-specific; they exercise the same hook engine CoalHearth's PreInvocation/PostToolUse pair depends on. Across that probe series, every hooks.json location reachable from a headless CLI session has now been tried, and all were inert.

Scope, stated precisely so this is not read as more disproven than it is: what has been tested is headless CLI hook firing. The 2026-08-22/08-23 probes ran under agy -p; the 2026-08-04 test's execution channel was not recorded. The interactive IDE (GUI-driven) path has never been exercised by any of these probes — it is a genuinely different execution path, and nothing here says whether the same config fires there. Nor is any of this a claim that AG's hook engine is broken in general (a sibling plugin's Stop hook did fire on 2026-07-12, above). works with here means "built + tested against the documented spec"; it has never meant "confirmed to fire," and no validated claim for Antigravity follows until a real fire is observed.

Install as a native plugin (Antigravity 1.3.1 has agy plugin install, but the proven route is a folder copy): copy the plugin folder to <project>/.agents/plugins/coalhearth (measured: both adapters fired and the resume block reached the model). A copy of the repository root and a plugins.json path entry were each measured to fire the journal leg (PostToolUse) only, so they are not a proven route for resume. Use a real directory: a Windows junction was not discovered (a symbolic link was not tried). agy plugin install https://github.com/TheColliery/CoalHearth.git puts the plugin in the global folder ~/.gemini/config/plugins/coalhearth/ (installed and listed, measured once), but the hooks firing from that folder were NOT measured: do not rely on it for the hooks (a location that looks right can silently not load, as the junction did). plugin.json and hooks.json at its root wire the two adapters; nothing else to configure. The older route, a hooks.json file copy, is below and is the one the negative tests used:

git clone https://github.com/TheColliery/CoalHearth.git --depth 1
# global (all workspaces):
Copy-Item -Recurse CoalHearth "$env:USERPROFILE\.gemini\config\skills\coalhearth"

Then copy platform-configs/hooks.json into <workspace>/.agents/hooks.json (per project) or ~/.gemini/config/hooks.json (global), and replace __COALHEARTH_DIR__ with the copied directory. Event mapping (AG never fires SessionStart): warm-resume rides the first PreInvocation of a session — a per-session temp marker keeps it once-per-session, since PreInvocation fires per model call — and the journal rides PostToolUse.

Known limits on AG: no fire was observed through a global or project hooks.json — three independent negative tests (2026-08-04, plus headless agy -p probes on 2026-08-22 and 2026-08-23 against the shared ~/.gemini/config/hooks.json), with real tool execution confirmed in each — see above for what was ruled out; the plugin path above is the one observed to fire. No probe has reached the interactive IDE (GUI-driven) path, so an IDE user's result is unknown rather than negative · the injected context (the injectSteps/ephemeralMessage JSON) was delivered on the plugin path (the model quoted it), on that one headless setup only · the UserPromptSubmit nudge and commands/*.md do not carry over · the AG tool-name map is best-effort beyond write_to_file (an unmapped tool is simply not journaled — never a wrong write) · the once-per-session temp markers are OS-reaped, not hook-deleted (AG has no end-of-session event) · the self-update nudge is deliberately not ported (its payload is a Claude-Code plugin command; on AG, update by re-copying).

Gemini CLI · Copilot CLI · Devin CLI · Kiro · Augment — works with (config-only ports)

Each of these ships a native session-start-class event, so none needs Antigravity's once-per-session marker workaround — the wiring is a config file pointing both events at the same two adapter entry points (bin/ag-pre-invocation.js + bin/ag-post-tool-use.js), switched by a trailing argument (SessionStart = Gemini's nested hookSpecificOutput emit · FileCopy = the plain Claude-Code shape the other four model). Clone the repo, copy the platform's template from platform-configs/hooks/ into place, and adjust the clone path — per-platform paths, verified-vs-best-guess notes, and the named divergences live in that directory's README. Same honesty as Antigravity: works with, not validated — no live session on these platforms has run the wiring yet.

Other agents — not supported

CoalHearth is hook-only, and it needs the session-start + per-tool event pair: a platform with no hook layer has nothing to run; a platform missing half the pair can't carry the product (Junie — session-start only; Devin Desktop's Cascade vocabulary — no session-start; see the matrix). Platforms whose hook surface is plugin CODE rather than a config file (OpenCode, Cline CLI) are a separate future lane. There is no read/analyze mode to load by hand (the way CoalMine or CoalLedger ship one).

Commands

CoalHearth's core value is its two automatic hooks (above); the two commands below are the only invokable surface — self-update and a read-only stats report.

Command What it does
/coalhearth:stats Journal activity and resume events for this session — read-only.
/coalhearth:update Check for a newer CoalHearth version and offer to apply it, or set how updates are handled.

⚙️ Configure

Everything is tunable in coalhearth.json (global ~/.claude/.coalhearth.json overlaid by a project config — per-group for a nested key, whole-value for a top-level scalar like language; the project lookup walks up from the cwd and stops at your home dir). Most keys are project-wins, so you can re-tune a globally-installed CoalHearth per project — the closest per-project quiet switch is recovery.autoInjectPrompt: false (detect + sweep silently, no recovery block; the journal hook still runs — full off = uninstall). Every key is optional.

Per-project config location — THE READ ORDER IS A RAIL, identical in every room of this series:

  1. <project>/.<the running agent's OWN dir>/coal/coalhearth.json — the dir of the agent actually executing (Claude Code = .claude, Antigravity = .agents, Gemini CLI = .gemini). This is the canonical path — under Claude Code, exactly .claude/coal/coalhearth.json.
  2. Other known agent dirs, fixed order: .claude → .agents → .gemini (first found wins).
  3. DEPRECATED — <project>/.claude/.coalhearth.json (the nested legacy shape). Still read, after every canonical path. Before this release the loader never read it at all.
  4. DEPRECATED — <project>/.coalhearth.json at the project root (the pre-2026-08-08 shape). Still read, always last.

Both legacy shapes are deprecated, and nothing breaks yet — but move your config. Put the same content at .claude/coal/coalhearth.json (or the running agent's own dir), or set any value with node scripts/configure.mjs (below), which writes the canonical file and removes the legacy one for you (unless git tracks it or cannot say whether it does (a repository git refuses to read): that legacy file is kept, and the script prints the git rm line to run after you review the change). Deprecated at the 2.5.0 MINOR; removable no earlier than the next MAJOR. This room owns the migration. This README note and the CHANGELOG ### Deprecated entry are the announcement — ship-text only, because a hook has no sanctioned channel of its own to announce on (Phoenix #13).

What you see when a legacy path is actually hit. That is a separate, smaller thing from the announcement: one line per finding on the SessionStart context-injection channel this room already holds sanctioned (the same one as the recovery block and the language directive), naming the path and the replacement — [CoalHearth] LEGACY: <path> is deprecated but still read; canonical = .claude/coal/coalhearth.json. A config-looking file at a path that is not in the read order above at all (say .claude/coalhearth.json, missing the coal/) gets [CoalHearth] IGNORED: <path> is not a config path; canonical = .claude/coal/coalhearth.json. A config that is at a path the walk reads but cannot be used gets [CoalHearth] UNREADABLE: <path> exists but is not a readable config (<reason>); it was skipped — canonical = .claude/coal/coalhearth.json, where <reason> is one of malformed JSON, a directory, unreadable (the OS refused the read, the file is over 1 MiB, or it is not a regular file or is a link that leaves the project) or not a JSON object (valid JSON that is an array, a string, a number or null). The global ~/.claude/.coalhearth.json is checked too, and when it is the one that failed the line ends with the global file's own path instead (canonical = <that path>), because a global config has no project location to move to. An unreadable legacy file gets UNREADABLE only, never also LEGACY. "Skipped" means the file contributes no settings; it does not open the door to a lower-priority config, because the walk still stops at the first path that holds a file. The line is appended to whatever SessionStart is already saying, or printed on its own when the session would otherwise be silent. It repeats every session for as long as the legacy file exists — once per session, not once ever — so a nudge that keeps appearing is working, not stuck; migrating is what silences it. A readable canonical config on its own, or none at all, prints nothing.

What it does not tell you: a config at a real path in the read order that simply loses is not announced. Only the first config found is ever read, so a legacy file left beside a canonical one, a second agent dir's canonical file, or the root .coalhearth.json once the nested one exists is silently dead — an edit to it will not take. Migrate it or remove it. (A directory sitting at a path in the read order is different: it is passed over — the walk counts a path only if it is a file, and a directory named like a config no longer anchors the project root — and, unless it sits after the config that is read, it is reported as UNREADABLE ... (a directory) above; with no config read at all, every such directory is reported.)

If you hold both legacy files, the nested one now wins. Before this release only the root .coalhearth.json was read, so .claude/.coalhearth.json was dead; now it is read first. Your effective config can change without you editing anything — and the notice above names the file now being read, not the root file that just went dead, so check for both, keep the file you mean and migrate it.

Write target = wherever the config was found — except that a config found at either legacy path is migrated on write (configure.mjs writes the canonical file and removes the legacy one, unless git tracks it or cannot say whether it does, in which case it keeps the file and prints a git rm -- <path> line for you to run; a hook never moves a file on a mere read); nothing found anywhere = the running agent's own dir. coalhearth.json still has no HOOK writer — the hooks that run every session never write config, only read it; that half of "always hand-edited" stays true. What changed: scripts/configure.mjs is now a USER-INVOKED CLI that edits it for you — node scripts/configure.mjs --language th — so "never written by CoalHearth itself" no longer describes the whole picture. Nothing runs it on your behalf; you or your agent runs it explicitly, the same way you'd run any other script in this repo. It refuses (exit 1, nothing written) a config it cannot treat as an ordinary file: one over 1 MiB, one that is not a regular file, or one reached through a link that leaves the project. It writes the config and its .bak through an exclusive temp file renamed into place, so a link planted at either is replaced, never written through, and it makes the .bak from the bytes it already read. --global still writes through a link at ~/.claude/.coalhearth.json, because dotfile managers link that file; its read is bounded too.

The high-impact keys, and the exact CLI flag for each (node scripts/configure.mjs <flag> <value>; --global targets ~/.claude/.coalhearth.json instead of the project config; node scripts/configure.mjs --help lists all seven):

Key Flag Default What it does
language --language auto Lock the reply language: auto / th / en / ja / zh / es. Top-level — not inside a group, unlike every other row here (see below).
recovery.autoInjectPrompt --recovery.autoInjectPrompt true Inject the recovery block on resume. false = detect + sweep silently, no injection.
recovery.stashUnsavedChanges --recovery.stashUnsavedChanges true Add a "consider git stash" line to the recovery block. false drops it.
update.updateMode --update.updateMode ask Self-update at session start: off schedules no check; ask, auto and remind all print the same consent-gated offer when a check is due (the hook does not tell the agent which one is set).

Every flag is the dotted key verbatim — --journal.outputDirectory (global only: it needs --global), --journal.atomicityRetries, and --update.updateCheckDays follow the same rows below and aren't repeated here; a flat --outputDirectory would spell one key two ways, so there is no shorthand form.

language sits at the top level of coalhearth.json, not nested under a group — {"language": "auto"}, never {"recovery": {"language": "auto"}}. auto (the factory default) follows the conversation's own language with an English fallback, no extra config needed. A lock (th/en/ja/zh/es) translates prose only — commands, paths, identifiers, config keys and severity labels stay verbatim regardless of the lock. What actually honors it: the SessionStart hook's own emissions (the recovery block, the journal-dir warning, the self-update nudge) append one directive naming the locked language when it is set to anything other than auto; nothing else in this room reads the key today.

Two exceptions to project-wins: update.updateMode and recovery.autoInjectPrompt gate an outward action (a nudge; the whole recovery-block injection), so a project .coalhearth.json — untrusted, it arrives with whatever repo you clone — can only QUIETEN either one relative to your global config, never re-enable something you turned off globally. Every other key (caps, paths, stashUnsavedChanges) stays plain project-wins.

Full key reference: every key + default lives in scripts/lib/config-schema.mjs and the commented template platform-configs/.coalhearth.json.

Permissions

CoalHearth requests the lightest profile in the series: it reads your project's planning files (task.md, AGENTS.md) and its own journal, and every write stays contained inside your workspace — never outside it. The exact destination is journal.outputDirectory, defaulting to its own namespaced .claude/coalhearth/; since 2.7.0 that key is read from your GLOBAL config (~/.claude/.coalhearth.json) only, because project config is untrusted (it ships with whatever repo you clone): a project .coalhearth.json that sets it is ignored everywhere, and on Claude Code reported once at session start. A value you set globally is contained to the workspace by containedOutputDir (lib/contained-dir.js) but not confined to CoalHearth's own state (the default folder itself is refused if a link is planted at it before a hook runs). No network, no exec, no subagent spawning, and no deletes beyond its own journal, temp, lock and scratch files: the disk-full prune acts only inside the project root's own .claude/coalhearth/ folder, and the resume-time sweep only in its scratch and worktrees directories. Hooks are its only lifecycle capability, capability-keyed to whatever hook engine the platform ships.

Full series matrix + the must-fail set: Permission Matrix

📊 Benchmark

Interruption damage, measured (2026-07-03, v1.0.0): on a 10-file mid-refactor, warm resume and cold restart both finished correctly with a <1% token delta — at small scale a strong model rebuilds state from the tree, so CoalHearth's token saving is a large-session effect. Its irreducible value is state fidelity: the in-flight sub-agent record a cold restart cannot reconstruct. Full table + honest scope: TheColliery/.github/benchmarks/CoalHearth.

🧭 Part of TheColliery

CoalHearth is the session-continuity member of the mining series, alongside:

Install one, it stands alone; install all, they compose without conflict.

Shared doctrine: Phoenix-13 hooks (zero-dependency, no network, fail-silent, no child processes, deterministic), single-source-of-truth config schemas, and a strict no-overkill discipline. Series doctrine: TheColliery/.github.

Zero-dependency, offline by default, no API keys — "by default" because the consent-gated self-update check (/coalhearth:update) goes online; the hooks never do.


📄 License

Apache License 2.0. See LICENSE.

About

Session warm-resume + handoff journal for AI coding agents - journals every step so an interrupted session resumes instead of rebuilding. Claude Code (validated) + 6 works-with ports (Antigravity, Gemini CLI, Copilot CLI, Devin CLI, Kiro, Augment). Reduces limit-hit damage; does not prevent it.

Topics

Resources

Code of conduct

Contributing

Security policy

Accessibility

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages