Brew a better handoff.
What is loopuccino
loopuccino is a pair: an Agent Skill that designs
the loop, and a CLI that checks the paperwork the loop leaves behind. The skill
turns iterative, long-running, or multi-agent AI work into an explicit contract —
what the outcome is, which evidence decides it, and when to stop without success.
The CLI is the deterministic gate on the way out: it reads one handoff.md and
reports whether the next session can resume from it without guessing.
Quick start
git clone https://github.com/Noah-TaeHwan/loopuccino.git && cd loopuccino
pipx install loopuccino # or: uv tool install loopuccino
loopuccino install --platform claude --apply # -> ~/.claude/skills/loopuccino
Start a new session in your agent and /loopuccino is available. The CLI is
published to PyPI (pipx install loopuccino / uv tool install loopuccino);
the Agent Skill wires in from the checkout via loopuccino install, which
symlinks the skill directory from the repository source.
The CLI
loopuccino init writes a starter handoff. It refuses to replace an existing
file unless you pass --force, and exits 2 when it refuses.
$ loopuccino init
loopuccino init: wrote handoff.md
loopuccino check reads one Markdown file, writes nothing, and exits 0 when
no errors were found.
$ loopuccino check handoff.md
loopuccino check: handoff.md
PASS CHECK-OK Required handoff contract checks passed
Result: PASS (0 errors, 0 warnings)
A document that is missing a required part fails with a diagnostic and exit 1:
$ loopuccino check bad.md
loopuccino check: bad.md
ERROR STRUCT-001 Missing required section: goal
Result: FAIL (1 errors, 0 warnings)
loopuccino check --contract adds the opt-in loop contract layer described
below.
loopuccino status reads a loop contract card and the loop-log.jsonl beside
it, and prints where the loop stands — so progress can be checked without
interrupting whatever is running. --all prints the three most recent events
instead of only the latest.
$ loopuccino status loop-contract.md
state in_progress (mode: durable)
last [round 3] verifier: pass — 18/18 re-verified
next Re-run the acceptance oracle, then record the result here.
loopuccino install wires the Agent Skill into an agent's skill directory. It
reports the target state and changes nothing until you pass --apply:
$ loopuccino install --platform claude
loopuccino install: platform=claude
source ~/src/loopuccino/skills/loopuccino
target ~/.claude/skills/loopuccino
status MISSING not installed
run again with --apply to perform the change
$ loopuccino install --platform claude --apply
loopuccino install: platform=claude
source ~/src/loopuccino/skills/loopuccino
target ~/.claude/skills/loopuccino
status OK symlink -> ~/src/loopuccino/skills/loopuccino
Both paths print in full; they are shortened to ~ here.
loopuccino update reports whether the installed CLI, the checkout, and
the skill wiring are in sync, and checks GitHub for a newer release
(offline is fine — the check degrades to local-only). Nothing changes
without --apply, which pulls the checkout and reinstalls the CLI:
$ loopuccino update
loopuccino update: checkout ~/src/loopuccino
cli 0.8.0 (installed)
checkout 0.9.0 (pyproject)
latest 0.9.0 (github)
skill claude OK symlink -> ~/src/loopuccino/skills/loopuccino
verdict cli 0.8.0 < checkout 0.9.0
action reinstall the CLI from ~/src/loopuccino
run again with --apply to perform the update
The handoff contract
The file must contain these H2 sections:
| Section | Purpose |
|---|---|
State |
state and previous_state values |
Goal |
The intended outcome |
Current state |
What is true now |
Done |
Completed work or acceptance items |
Blocked |
reason, owner, and decision_needed, or none for all three |
Changed files |
Files changed in the work session |
Verification |
command and result entries |
Next action |
The first useful action for the next session |
Resume command |
A concrete command, path, or document reference |
Allowed states are planned, in_progress, blocked, ready_for_review,
verified, handed_off, and closed. A verified or closed handoff needs a
recorded passing result such as passed, success, or green; loopuccino
does not rerun the command.
Start from the synthetic template in template/handoff.md.
loopuccino init writes that same file for you.
The loop contract
loopuccino check --contract handoff.md adds one optional layer on top of the
handoff contract. It checks whether the document declares the five parts of
an execution contract before anyone claims the work is done:
| Slot | Heading the checker looks for | What it adds over the handoff contract |
|---|---|---|
| Outcome and non-goals | Outcome and non-goals |
Goal states the intent; this states the observable result and what must not change |
| Authority and action boundary | Authority and action boundary |
Which inputs win, which acts are allowed, and which need approval |
| Current state and next action | Current state plus Next action, or a combined Current state and next action |
Already covered by the handoff contract; accepted in either form |
| Acceptance evidence | Acceptance evidence |
Verification records what was run and what came back; this declares up front which check decides which claim, and what it cannot prove |
| Bounds, stopping, and handoff | Bounds, stopping, and handoff |
Attempt, cost, and time bounds, what counts as no progress, and when to stop without success |
The flag is opt-in. Without it no CONTRACT-* diagnostic is ever emitted, so a
handoff that never adopted this contract is never failed for omitting it.
Why these checks read structure only
These checks decide one question: is each slot declared, non-empty, and
formatted as a declaration? They do not decide whether a declared outcome is
the right outcome, whether an action boundary is safe, whether the named
evidence actually proves the claim, or whether the work is genuinely finished.
Those are judgement calls, and a regular expression that imitated them would
produce confident output with nothing behind it. That would break the
safety boundary below: loopuccino reports structure and
does not vouch for truth.
The Agent Skill
The repository ships loopuccino as an Agent Skill. It is plain Markdown, so any harness that reads skill-style instructions can use it. It is meant to trigger when AI work is iterative, long-running, resumable, unattended, cross-session, high-risk, or multi-agent — the cases that need evidence-closed completion, explicit stopping, recovery, challenge, or handoff. Triggers are written in English and Korean.
The method is one contract and three modes. The contract names five things
before work starts: the outcome and non-goals, the authority and action
boundary, the current state and next action, the acceptance evidence
that decides which claim, and the bounds, stopping, and handoff rules. The
mode is the smallest mechanism that fits — micro when iteration fits in one
response, durable when the work must survive a context boundary, and
orchestrated only when independent evidence or disjoint parallel work actually
justifies coordination. The loop itself is ACT -> CHECK -> DECIDE, with a rare
fresh-eyes challenge inside DECIDE when machinery is growing but evidence is
not.
For unattended or judged runs in Claude Code, read Claude Code goal/loop and instantiate the thin goal and loop templates per project. Other harnesses reuse the same templates; only the command surface differs.
Cross-agent install matrix
| Platform | Target | Method | Notes |
|---|---|---|---|
claude |
~/.claude/skills/loopuccino |
symlink | Tracks the checkout; pulling the repo updates the skill |
codex |
~/.codex/skills/loopuccino |
symlink | Same as above |
agents |
~/.agents/skills/loopuccino |
symlink | Same as above, for harnesses that read ~/.agents/skills |
hermes |
<--dest>/loopuccino |
copy | --dest is required; commit the copy in that repository and redeploy so its runtime picks it up |
Without --apply the command only reports each target's state:
| Status | Meaning |
|---|---|
OK |
Installed and pointing at this checkout |
MISSING |
Nothing at the target path yet |
STALE |
A symlink pointing somewhere else; --force replaces it |
CONFLICT |
A real directory is in the way; loopuccino refuses to touch it |
Real directories at a target path are never removed. For hermes, --force
refreshes the copy.
Design principles
- Smallest mode. The skill starts at the least machinery that can work, and does not promote to durable or orchestrated modes just because tools and agents happen to be available.
- Evidence-closed completion.
COMPLETEDrequires the declared success condition to be evaluated true with the evidence it named up front. A budget limit, a tool that returned, or a partial check is never completion by itself. - Truthful stopping. When a bound is reached, the honest answers are
PARTIAL,BLOCKED, orSTOPPED, with the best-known artifact preserved — not a claim of success and not a promise to report later. - Privacy lint. This repository holds itself to the same standard: a test in the suite scans every tracked text file for private tokens and fails CI if one appears, so nothing from a working session leaks into a public artifact.
Diagnostics and exit codes
STRUCT-001: required section is missing.STRUCT-002: required section is empty.STATE-001: state is missing or not allowed.STATE-002: previous-to-current state transition is not allowed.STATE-003:verifiedorclosedhas no passing verification result.RESUME-001: blocked handoff is missing a reason, owner, or decision.RESUME-002: next action has no explicit target or command.EVIDENCE-001: non-final state has no passing verification result; this is a warning.
With --contract:
CONTRACT-001: a loop contract slot is not declared.CONTRACT-002: a declared slot has no content.CONTRACT-003: a declared slot still holds only unfilled<placeholder>text. A line counts as a placeholder when it is exactly one<...>token, optionally preceded by a list marker and alabel:and optionally wrapped in backticks; the slot is only reported when every one of its non-blank lines is such a line, so this check under-reports rather than guesses.CONTRACT-004:Acceptance evidencelabels noStructural,Semantic,Operational, orSuccessline; this is a warning, because a label is only weak evidence that the planes were actually separated.
| Exit code | Meaning |
|---|---|
0 |
No errors; warnings may be present. |
1 |
Handoff contract errors were found. |
2 |
Usage or input-file error. |
3 |
Unexpected checker error. |
Safety boundary
loopuccino is deliberately local and deterministic:
- It uses only the Python standard library at runtime.
checkreads one Markdown file and writes nothing.initwrites one file at the path you name, and will not replace an existing file unless you pass--force.installonly touches the filesystem: no network, Git, or shell calls.updateis the one command that reaches further: it may query the GitHub releases API (a single read-only request; nothing is uploaded), and with--applyit runsgit pull --ff-onlyand reinstalls the CLI.check,init,status, andinstallnever touch the network, Git, or a shell.- It does not execute commands found in the handoff.
- Outside of
update, it does not inspect Git or the filesystem beyond reading the input path. - It does not scan secrets, call a model, or upload content. Outside of
update's single read-only release check, it makes no network requests. - It emits human-readable output only.
- It judges the structure of what a document declares. It never judges whether those declarations are true, adequate, or well chosen.
Development
uv sync --extra test
uv run pytest -q
uv build
The project targets Python 3.9 through 3.13. Pull requests run the same test
suite across that matrix. Released changes are recorded in
CHANGELOG.md.
Name
loopuccino is pronounced loop-oo-CHEE-no — loop plus cappuccino, which is
also what the mark draws: steam off the crema tracing a loop. The canonical
spelling is lowercase loopuccino for the brand, package, repository, and
command. Brand files live in
assets/brand/.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loopuccino-0.10.0.tar.gz.
File metadata
- Download URL: loopuccino-0.10.0.tar.gz
- Upload date:
- Size: 41.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ab6925e5829fc8cf772040347fac72bbf74c7e66412260d38985c39366e1122c
|
|
| MD5 |
30e66e7df704e49056e0d133252ce3ba
|
|
| BLAKE2b-256 |
e654b518deddf19f4c7a17323c04db96f65edb0c331b192aacffa702c24e5470
|
Provenance
The following attestation bundles were made for loopuccino-0.10.0.tar.gz:
Publisher:
publish.yml on Noah-TaeHwan/loopuccino
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loopuccino-0.10.0.tar.gz -
Subject digest:
ab6925e5829fc8cf772040347fac72bbf74c7e66412260d38985c39366e1122c - Sigstore transparency entry: 2358339863
- Sigstore integration time:
-
Permalink:
Noah-TaeHwan/loopuccino@2decdee402fff1c8e25f1a07742b24560e2cc22c -
Branch / Tag:
refs/tags/v0.10.0 - Owner: https://github.com/Noah-TaeHwan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2decdee402fff1c8e25f1a07742b24560e2cc22c -
Trigger Event:
push
-
Statement type:
File details
Details for the file loopuccino-0.10.0-py3-none-any.whl.
File metadata
- Download URL: loopuccino-0.10.0-py3-none-any.whl
- Upload date:
- Size: 25.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d4c1a6a05a5faa5128cb6f5c6ef52de64166e4ea4fe35b0f2fe8a01281a7c648
|
|
| MD5 |
3579534c72d9ad61a817ec56d6048427
|
|
| BLAKE2b-256 |
80becf221d00d580c2a654b7f5062a4c36e0c87f0ef57334d1a65d7b5bfb6d68
|
Provenance
The following attestation bundles were made for loopuccino-0.10.0-py3-none-any.whl:
Publisher:
publish.yml on Noah-TaeHwan/loopuccino
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loopuccino-0.10.0-py3-none-any.whl -
Subject digest:
d4c1a6a05a5faa5128cb6f5c6ef52de64166e4ea4fe35b0f2fe8a01281a7c648 - Sigstore transparency entry: 2358339993
- Sigstore integration time:
-
Permalink:
Noah-TaeHwan/loopuccino@2decdee402fff1c8e25f1a07742b24560e2cc22c -
Branch / Tag:
refs/tags/v0.10.0 - Owner: https://github.com/Noah-TaeHwan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2decdee402fff1c8e25f1a07742b24560e2cc22c -
Trigger Event:
push
-
Statement type: