A Claude Code session forgets everything the moment it ends. iris is the layer that remembers — then keeps working. It writes its own handover before context compaction and loads it at the next session start, runs your backlog end to end (implement → verify → commit → repeat), decides for itself when to parallelize, and lets you queue the next ideas mid-run. /manager takes it wider: a recursive tree of managers and workers across several projects at once, scheduled off a real dependency graph. Flip on /takeover and it runs unattended — choosing its own objectives, guided by a second brain that learns how you decide. Plain files. No daemon. No lock-in.
git clone https://github.com/sohams25/iris.git ~/Tools/iris
cd <your-project> && bash ~/Tools/iris/setup.shWhen context compaction fires — or you run /rollover — iris writes a handover: standing instructions, open threads, branch state, what changed. Claude writes it; the SessionStart hook injects it at the top of the next session. You stop re-explaining your project every morning, and decisions stop evaporating between sessions.
docs/plan.md is a YAML backlog. /run works it without a babysitter — picks the next task, implements it, runs your verify command, commits on green, and loops. It inspects the work and routes itself: one task or shared files run serially; a batch of file-disjoint tasks fans out into parallel waves, with the width chosen automatically. Point it at the backlog and walk away.
Jot the next tasks into docs/next.md while a run is in flight. The loop folds them into the backlog at the next safe checkpoint — between tasks, never mid-task — so your planning and its execution stay in sync without ever colliding.
/takeover on and iris runs unattended — it decides the next objective itself (and invents goals when the backlog runs dry), executes through /run, learns from how it went, and loops. It's guided by a second brain: a local, private model of your preferences that updates with a reward rule on outcomes and simulates what you'd choose at each fork. Experience replay + consolidation keep what it learned about a long project from being forgotten as it picks up new patterns. /takeover off is the kill-switch; cycle/time budgets and a full audit trail keep it bounded; verify-before-commit is never skipped.
/manager is the layer above /run. Tasks form a tree: a manager owns an objective and delegates to children, and any child may become a manager itself. Alongside it runs a dependency DAG (what must land first) and a resource conflict graph (what must not run at the same time — same file, same board, same GPU). One deterministic scheduler reads all three and decides what starts next.
Each active task gets its own Claude context. What flows back up is not a transcript — it is four short fields:
M001 EarlyOn investigation [RUNNING]
├── M001.1 Reproduce regression [DONE]
├── M001.2 Deployment investigation [RUNNING]
│ ├── M001.2.1 ISP [RUNNING]
│ └── M001.2.2 GStreamer [DONE]
└── M001.3 Validation [BLOCKED: waits for M001.2]
dependencies:
M001.2 -> M001.3
manager · 6 tasks · 2 running · 1 blocked
P1 M001 RUNNING Root cause identified; validation underway.
-> M001.3 Validation
M001.2 RUNNING ISP issue isolated; testing the workaround.
M001.3 QUEUED waits for M001.2
P2 M002 RUNNING Documentation restructuring complete.
-> final consistency pass
next: M001.2, M002
inbox: empty
Detailed context stays at the lowest useful level; compressed state moves upward. The root manager reads M001's brief, never M001.2.1's session log — which is what keeps the token cost of ten workstreams roughly the cost of one. Identity, cycle detection, state transitions, conflicts, scheduling, leases, and recovery are all plain Python; judgment is Claude's. See docs/manager-design.md.
%%{init: {'theme':'base','themeVariables':{'background':'#050506','primaryColor':'#11131d','primaryTextColor':'#ECEDF1','primaryBorderColor':'#5E6AD2','lineColor':'#5E6AD2','textColor':'#9aa1b8','fontFamily':'ui-monospace, monospace','clusterBkg':'#0a0a0e','clusterBorder':'#23253a'}}}%%
flowchart LR
you([you]) -. jot ahead .-> next["docs/next.md"]
next -. drained between tasks .-> run
subgraph s[" Claude Code session "]
run["/run · self-routing loop"]
hooks["hooks"]
end
run --> plan["docs/plan.md<br/>backlog"]
run --> route{"serial / parallel?<br/>auto"}
hooks --> mem[("memory<br/>markdown · obsidian")]
plan --> mem
%%{init: {'theme':'base','themeVariables':{'background':'#050506','primaryColor':'#11131d','primaryTextColor':'#ECEDF1','primaryBorderColor':'#5E6AD2','lineColor':'#5E6AD2','textColor':'#9aa1b8','fontFamily':'ui-monospace, monospace'}}}%%
sequenceDiagram
participant U as You
participant CC as Claude Code
participant H as hooks
participant M as memory
H->>M: SessionStart → load current handover
M-->>CC: yesterday's context, restored
U->>CC: /run
Note over CC: implement → verify → commit → loop<br/>(drains docs/next.md between tasks)
Note over CC: context fills up
CC->>H: PreCompact
H->>M: write the next handover
M-->>CC: continuity into the next session
iris installs alongside an existing Claude Code project.
git clone https://github.com/sohams25/iris.git ~/Tools/iris
cd <your-project>
bash ~/Tools/iris/setup.sh # symlinks .claude/ + scripts/, copies templates, runs doctorsetup.sh symlinks .claude/{commands,hooks,skills}/ and scripts/ into your project, copies CLAUDE.md, docs/plan.md, and docs/next.md templates if missing, scaffolds $PROJECTS_DIR/, generates .env, and runs scripts/doctor.py (17 health checks). Open a session and try /status.
| Command | Does |
|---|---|
/run |
Work the backlog: drains docs/next.md, auto-routes serial vs parallel, verifies + commits each step |
/manager [...] |
Many workstreams at once: recursive managers, dependency scheduling, independent Claude contexts, crash recovery |
/takeover [on|off|status] |
Hands-off autonomous work, guided by the learning second brain (off = kill-switch) |
/status |
Open tasks · current handover · branch · last commits |
/backlog [Tnnn] |
The backlog as a table, or one task by id |
/submit <desc> |
Refine a raw idea into a T### entry |
/rollover [title] |
Write a handover checkpoint now, with carry-forward |
/memory [current|list|search|validate] |
Inspect the memory backend |
/doctor |
Run the 17 health checks |
/new-task <slug> |
Scaffold $PROJECTS_DIR/<N>_<slug>/ with README + docs/ + archive/ |
Plan ahead by editing
docs/next.mddirectly while/runis going — no command needed./planbelongs to Claude Code's built-in plan mode.
Two backends, one CLI — switch with MEMORY_BACKEND in .env.
| Backend | Storage | For |
|---|---|---|
markdown (default) |
handovers/handover_NNN.md at repo root |
Zero deps, plain files, grep-friendly, isolated per project |
obsidian |
$OBSIDIAN_VAULT/work/handovers/<project>/ |
Handovers searchable inside your vault, namespaced per project |
scripts/migrate-handovers.py lifts an existing markdown corpus into a vault, preserving the prev/next chain as [[wikilinks]].
iris resolves repo root from $IRIS_ROOT (else the working directory) on every call, so each project's handovers/, .iris-state/, docs/plan.md, and docs/next.md live under that project. Open a session in repo A and another in repo B — handovers, run locks, and backlogs never cross. The obsidian backend namespaces handovers per project under work/handovers/<project>/; the markdown default needs no configuration. tests/test_multiproject_isolation.py pins both.
iris's core has no idea Slack exists — it just exposes scripts/*.py and the slash commands. An adapter under integrations/<name>/ wraps those for its medium, so the same loop can drive your team's chat.
integrations/
├── slack/ # reference adapter — ships
├── discord/ # documented stub
└── webhook/ # documented stub
Copy integrations/slack/ to integrations/<name>/, retarget its sender/receiver, add an env stub. See docs/integrations.md for a worked example.
iris/
├── .claude/
│ ├── commands/ · 10 slash commands
│ ├── hooks/ · session-start · pre-compact · block-ai-trailers · brain-observe (opt-in)
│ ├── skills/ · handovers · manager · swarm (parallel engine) · commit-style · karpathy-guidelines
│ └── settings.json
├── scripts/
│ ├── iris_core/ · the shared core — one implementation, every caller
│ │ ├── model.py · task shapes + the state machine
│ │ ├── ids.py · canonical ids, derived M-paths
│ │ ├── graph.py · ownership tree + dependency DAG + cycle detection
│ │ ├── conflicts.py · resource keys, conflict predicate, waves
│ │ ├── scheduler.py · ready frontier, ordering, safe parallel sets (pure)
│ │ ├── aggregate.py · hierarchical brief rollup
│ │ ├── refs.py · M001 / name / partial-name resolution
│ │ ├── store.py · per-task dirs, atomic writes, authorisation
│ │ ├── leases.py · claims · heartbeats · run lock · crash recovery
│ │ ├── execution.py · the Claude Code execution adapter
│ │ └── plan_bridge.py · docs/plan.md → the shared scheduler
│ ├── manager.py · the /manager CLI (thin; logic lives in iris_core)
│ ├── _iris_paths.py · shared repo-root resolution (the multi-project core)
│ ├── memory.py · CLI over both memory backends
│ ├── queue.py · plan-ahead queue: drains docs/next.md → backlog
│ ├── build-wave-plan.py · compat CLI over iris_core.scheduler (--decide)
│ ├── brain.py · the second brain (RL preference model + simulate)
│ ├── takeover.py · autonomous-takeover gate (toggle · budgets · kill-switch)
│ ├── parse-tasks.py · doctor.py (17 checks) · handover-new/validate · migrate-handovers
│ └── notify.py · detect-verify.sh · slackbot-start.sh
├── integrations/ · slack (ships) · discord · webhook (stubs)
├── tests/ · primitives · hooks · adapters · multi-project · skills · queue · router · brain
│ · takeover · manager identity/graph/scheduler/state/hierarchy/persistence/acceptance
├── docs/ · plan.md · next.md · integrations.md · architecture.md · manager-design.md
└── setup.sh · CLAUDE.md · Makefile · pyproject.toml
/run's parallel engine is the swarm skill; build-wave-plan.py --decide is what chooses to call it. Both, and /manager, schedule through the same iris_core.scheduler — there is deliberately no second algorithm hiding in a prompt.
/run, /takeover, and a /manager delegation all claim .iris-state/run.lock before they start, and refuse if another holds it. Two autonomous loops over one backlog corrupt each other's commits; the lease is what makes that impossible rather than merely discouraged. A holder that dies releases it after 900s, and manager.py reconcile never reads a vanished process as success — it pauses the task and keeps the worktree.
The eye's aperture that opens to let the light in, and the Greek goddess who carried messages between worlds. iris keeps your session in focus and moves what matters between it and everything around it — your terminal, your past sessions, your backlog.
MIT — see LICENSE.
- andrej-karpathy-skills — MIT; the
karpathy-guidelinesskill is vendored from it. - obsidian-mind — the vault format the obsidian backend writes against.
- superpowers · stop-slop — skills iris links in when present.
- Claude Code — the host. iris is plumbing; the agent does the work.