Skip to content
nixptPublic

About

Short-lived agents for Cursor, Claude, Codex, and friends — one task, then gone.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

mayfly

mayfly

Short-lived agents. One task. Then gone.

Ephemeral single-purpose workers for Cursor, Claude, Codex, OpenCode, and friends.

mayfly hatch examples/fix-test.json --worktree /path/to/repo
# → validate → buckets worktree → spawn harness → watch done_when / TTL → tear down → report

Not a teammate. Not a persona. A disposable specialist with a hard lifespan.

Current release: v0.1.6 · repo nixpt/mayfly

Why

Long-lived agent sessions expand scope, linger, and multiply. mayfly is the opposite contract:

rule meaning
One purpose exactly one task + one done_when
Hard lifespan TTL + budget; auto-teardown
Vague asks die at the hatch validate rejects open-ended tasks
Workers can't hatch others no recursive spawn
Harness-agnostic same schema; adapters per runner

For durable fleet work, use horses + agent-launch. For "fix this one thing and vanish", use mayfly.

Install

cargo install --git https://github.com/nixpt/mayfly --tag v0.1.6
# or from a checkout:
cargo install --path .
# binary: mayfly

Not yet installed on nixps (s463): nothing puts mayfly on PATH there.

Needs host harness binaries on PATH for the runners you use (cursor-agent, claude, codex, …). Optional: buckets for --worktree.

Model, read-only, budgets, success (MAYFLY-8)

Field claude / ccf codex / cxf opencode cursor / cece / exec
model --model -m -m (beats MAYFLY_OPENCODE_MODEL) refused
read_only: true --tools Read,Grep,Glob --permission-mode dontAsk --strict-mcp-config, no skip-permissions --sandbox read-only refused refused
budget.max_usd --max-budget-usd refused refused refused
budget.max_turns not enforced (no CLI turn cap); validate prints a note same same same

"Refused" means validate/hatch exit 2 before anything is created. A knob that would be silently ignored is worse than a refusal: the caller would believe a cheap, read-only, capped run happened.

A read-only hatch can't write files, so its done_when must not require writes. Its answer is the harness's stdout (stdout_tail in the report).

Success requires done_when to pass (and the harness to exit 0). MAYFLY_DONE printed without a passing done_when is recorded as a failed claim, not a success. For exec, the exit code must equal expect_exit. A failed hatch never exits 0, even when the harness did.

Per-project runners and state (MAYFLY-9)

In a repo that has adopted .jagent/ (the fleet's v2 layout), mayfly keeps both halves with the project:

What Where Committed?
Runners: named partial tasks of defaults (harness, model, read_only, ttl, budget, constraints, aging) <repo>/.jagent/agents/mayfly/<name>.json yes (list mayfly/*.json under [commit] in .jagent/agents/.manifest)
Hatch records (list/status/expire) <repo>/.jagent/local/mayfly/ no (gitignored .jagent/local/)
mayfly init-runners                        # scaffold read.json (claude, haiku, read_only, 10m, $0.25) + README; never overwrites
mayfly runners                             # name  harness  model  read_only  ttl
mayfly hatch task.json --runner read       # runner defaults merged under the task
mayfly validate task.json --runner read

Merge rule: the task's fields win, and nested objects (budget, constraints, aging) merge key by key. Arrays and scalars are replaced. task and done_when must come from the task; a runner that sets them is rejected. An unknown --runner exits 2 and lists the known ones.

State dir precedence: --state-dir > MAYFLY_STATE_DIR > <main checkout>/.jagent/local/mayfly (when the task's cwd, or the caller's for list/status, is inside a repo whose main checkout has .jagent/; linked worktrees resolve to their main checkout) > ~/.local/state/mayfly. mayfly warns if .jagent/local/ isn't gitignored. It never creates .jagent/ in a repo that hasn't adopted it: runner commands exit 2 there, and state falls back to home. .jagent/state/ is reserved for squadron and never used.

Usage

# Check a task without spawning
mayfly validate examples/fix-test.json

# Hatch (dry-run prints the plan; omit --dry-run to launch)
mayfly hatch examples/fix-test.json --dry-run

# Hatch into a throwaway git worktree (public nixpt/buckets — on PATH)
mayfly hatch examples/fix-test.json --worktree /path/to/repo
mayfly hatch examples/fix-test.json --worktree . --branch mayfly/demo --keep-worktree

# Watch / force end
mayfly status <id>
mayfly expire <id>
mayfly list

--worktree shells out to buckets worktree create/remove (no crates.io path-dep). Flame/firefly are intentionally not used for hatch cwd — different layer.

Task file (minimal)

{
  "task": "Fix the failing test in foo::bar::test_baz",
  "done_when": {
    "type": "command",
    "run": "cargo test -p foo bar::test_baz -- --exact",
    "expect_exit": 0
  },
  "harness": "cursor",
  "cwd": ".",
  "ttl": "15m"
}

See DESIGN.md for the full contract (aging ladder, adapters, fuzziness gate).

Harnesses

id adapter notes
cursor cursor-agent -p --yolo --trust smoke OK @ v0.1.x
ccf same argv as claude needs fleet ccf/flownet Anthropic env — smoke OK
cxf codex --profile flownet exec … needs FLOWNET_TOKEN_CODEX — smoke OK
opencode opencode run --auto --dir … set MAYFLY_OPENCODE_MODEL (e.g. opencode/big-pickle) — smoke OK
claude claude -p … --dangerously-skip-permissions needs Anthropic or ccf env
codex codex exec --sandbox workspace-write … raw Codex; prefer cxf on this fleet
cece cece-rs -w … -p … --afk fleet binary; subject to provider budget
exec sh -c <done_when> no LLM — smoke OK

Fleet wrappers ccf / cxf are shell functions; export their env (or run under a login zsh that defines them) before mayfly hatch with harness ccf/cxf.

Optional smoke (needs jq + harness on PATH):

cargo build --release
MAYFLY_BIN=./target/release/mayfly ./scripts/smoke-harness.sh cursor
MAYFLY_BIN=./target/release/mayfly ./scripts/smoke-harness.sh cxf   # FLOWNET_TOKEN_CODEX
MAYFLY_BIN=./target/release/mayfly ./scripts/smoke-harness.sh ccf   # ANTHROPIC_* flownet env
MAYFLY_OPENCODE_MODEL=opencode/big-pickle \
  MAYFLY_BIN=./target/release/mayfly ./scripts/smoke-harness.sh opencode

Missing harness binaries error clearly (harness '…' binary … not found on PATH) instead of hanging.

Fleet usage (horse → mayfly)

From a dispatched horse or any shell with buckets + mayfly on PATH:

mayfly hatch /path/to/task.json --worktree "$REPO"
# provisions sibling worktree via buckets, runs harness, tears down with --force

Prefer mechanical done_when + TTL ≤ 2h. Durable multi-step work stays on horses/agent-launch.

Relationship to the fleet

foreman / horse     → multi-step, memory, merge
mayfly              → throwaway *agents* (harness + TTL)
agent-launch        → resource-controlled durable dispatch
buckets             → throwaway *runtimes* + *worktrees* (mayfly uses worktree)
flame / firefly     → workspace OS (heat/brands/fuel) — held, not wired

Self-contained: no path deps on peer projects.

Agent memory & planning

path role
.dejavue/ architectural memory — dejavue context boot packet
.jagent/ planning board — MAYFLY-NN tickets in .jagent/planning/
scripts/bump-version.sh conventional-commit bumps on push to main (see .github/workflows/release.yml)

Brand assets

The project logo, monochrome mark, and social preview are in assets/. See assets/README.md for usage and palette details.

License

Licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Short-lived agents for Cursor, Claude, Codex, and friends — one task, then gone.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages