New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

sagloop

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sagloop

Simple agentic loops: run a markdown checklist one item at a time with a fresh agent session for each

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
4
33.33%
Maintainers
1
Weekly downloads
 
Created
Source

sagloop

Simple agentic loop. Run a markdown checklist one task at a time, with a completely fresh agent session for each task.

npx sagloop plan.md

sagloop is a while loop over claude -p (or opencode run). Each iteration starts a brand new harness process, hands it your document, and tells it to complete the first unchecked box. When the process exits, sagloop re-reads the document, confirms the box got checked, prints a status line, and starts the next iteration with zero carried-over context.

The document is the state. Stop it, edit it, run it again and it picks up where it left off.

Why

Long agent sessions get worse as context grows. The fix is to stop carrying the context: finish one step, throw the session away, start the next one clean.

Claude Code's own repetition tools are built to keep a session going rather than to start a new one. /loop re-fires your prompt into the same conversation on a timer. /goal keeps that same conversation working until a separate evaluator agrees the condition is met. Todo lists track progress inside one context window. Each of them accumulates the context you were trying to shed. Subagents do get a clean window per task, but the plan stays in the parent session, so you cannot stop it, edit the steps that are left, and pick up from there.

Ralph-style loops do reset between steps, but a shell loop around claude -p has no way of telling whether a step actually happened. sagloop keeps the reset and adds the parts that make it usable unattended: a contract for what counts as done, failure handling that separates a crash from a refusal, and a run you can read afterwards.

Writing a document

Any markdown file works. Every task-list item in it is a task, in document order, nested items included. Everything else is context the agent reads before it starts.

# Add a --json flag

## Context

The CLI lives in src/cli.ts. Tests use node:test. Commit after each task
with a conventional commit message.

## Tasks

- [ ] Add a failing test for parsing --json
- [ ] Make it pass
- [ ] Document the flag in the README

Tips that make docs go well:

  • Put everything the agent needs in the context section: file paths, test commands, constraints, conventions. Each iteration starts from nothing.
  • Make each task small enough to finish in one sitting and verifiable on its own. "Add a failing test" then "make it pass" beats "implement the feature".
  • Tell the agent to commit if you want commits. sagloop never touches git.
  • Checkboxes inside fenced code blocks are ignored, so you can show examples.
  • Work the document up with your agent first. Something like Matt Pocock's grill-me skill produces exactly this shape.

Check what sagloop sees before running anything:

sagloop plan.md --dry-run

The contract

Each iteration the agent receives a fixed prompt with the absolute path to your document:

  • Read the entire document. The prose is context, the checkboxes are tasks.
  • Complete the first unchecked task and only that task.
  • Check it off by changing - [ ] to - [x].
  • Optionally add a short note as an indented bullet under the task, for anything a later task needs to know (files created, decisions, gotchas). Edit nothing else.
  • If you cannot complete it, leave it unchecked and explain why.
  • Stop.

Then sagloop compares the document before and after:

What happenedWhat sagloop does
First unchecked box is now checkedPrints a status line, starts the next iteration
More boxes flipped, or a different oneAccepts it, prints a warning, continues
Nothing flipped, harness exited cleanlyStops, exit 1, prints the agent's final message
Harness exited non-zeroRetries up to 3 times with backoff, then exit 1
Harness hit the timeoutStops, exit 1. Not retried
All boxes checkedExit 0

The agent leaving a box unchecked is the "I'm blocked" signal. sagloop does not retry that, because re-asking an agent that just read the task and declined is how loops get expensive. Fix the document and run again.

A timeout is not retried either. It means the task did not fit in the limit, and a second attempt spends the same wall clock to reach the same place. Raise --timeout or split the task.

Usage

sagloop <doc.md> [options] [-- <harness args>]

  -H, --harness <name>        claude | opencode (default: $SAGLOOP_HARNESS or claude)
  -m, --model <name>          passed to the harness's model flag (default: $SAGLOOP_MODEL)
  -n, --max-iterations <n>    stop after n completed tasks
      --once                  same as --max-iterations 1
  -t, --timeout <duration>    per-task wall clock limit, e.g. 90s, 30m, 1h (default: 1h)
  -P, --permissions <mode>    auto | bypass | harness (default: $SAGLOOP_PERMISSIONS or the
                              harness default: auto for claude, bypass for opencode)
      --log-dir <dir>         write a transcript and the raw harness output per run
      --dry-run               show the parsed tasks and the command, then exit
      --no-color              disable ANSI colors

Anything after -- goes to the harness verbatim:

sagloop plan.md -H opencode -m anthropic/claude-opus-4
sagloop plan.md -- --add-dir ../shared

Permissions

Headless runs cannot answer permission prompts, so something has to decide. --permissions picks what, and sagloop prints the choice on startup.

Modeclaudeopencode
autoDefault. --permission-mode auto plus --permission-prompts none: Claude Code's classifier approves or denies each action, and anything it would have asked a human about is denied.Not available.
bypass--dangerously-skip-permissionsDefault. --dangerously-skip-permissions
harnessNo flags. Your configured allow and deny rules apply, and anything that would prompt is denied.No flags.

When the harness reports that tool calls were denied, sagloop prints a warning with the tool names. If an agent declines a task right after a denial, that is usually why.

Logs and sessions

Every iteration prints the command that reopens that agent's session, so you can go and read what it actually did:

  ↺ claude --resume 5ed0a8ef-721c-4935-80e3-eeb482974247

When a run stops early - declined, failed, timed out, interrupted - sagloop repeats that command as its last line, where you will actually notice it.

--log-dir keeps the whole run on disk. Each invocation gets its own timestamped directory, so re-running never overwrites the last one:

logs/2026-09-04T05-27-37/
  sagloop.log          everything sagloop printed, minus the colors
  001.jsonl            the harness's raw stream for iteration 1
  002.jsonl
  002.attempt2.jsonl   a retry, after the process crashed
  002.stderr.log       written only if the harness wrote to stderr

The raw streams carry the session id on every line, so a loop left running overnight is still inspectable in the morning.

Stopping

Ctrl-C forwards SIGINT to the harness, waits five seconds for it to wind down, then kills it. Press Ctrl-C again to skip the wait. Exit code 130. The document is whatever the agent left, so re-running resumes correctly.

Exit codes

CodeMeaning
0All tasks done, nothing to do, or max iterations
1Agent declined a task, timed out, or retries exhausted
2Usage error, missing document, or harness not found
130Interrupted

Harnesses

NameCommandNotes
claudeclaude -p --output-format stream-jsonDefault. Supports auto permissions. Cost reported per iteration.
opencodeopencode run --format jsonNo auto mode, defaults to bypass. Model names look like provider/model.

Codex is not supported yet.

Development

npm install
npm test            # unit and integration tests, no network
npm run typecheck
npm run build       # emits dist/

Integration tests run the loop against a fake harness that speaks the real stream-json protocol and edits the document. To run one real iteration against an installed harness (costs tokens):

SAGLOOP_SMOKE=claude node --test test/smoke.test.ts

License

MIT

Keywords

agent

FAQs

Package last updated on 04 Sep 2026

Related posts