Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bc27c07
feat: Extend sloop check with manifest-sourced readiness criteria
tuanngo Jun 28, 2026
f47875a
feat: Keep init minimal and provider-respecting (per-workspace tools)
tuanngo Jun 28, 2026
420094a
fix: Make init prompts honest — ask about every tool, skip done work
tuanngo Jun 28, 2026
761aba6
fix: Honest scaffolding and Claude-first tool order in init
tuanngo Jun 28, 2026
5234f50
fix: Don't ask to scaffold provider folders in init (provider-respect)
tuanngo Jun 28, 2026
905f65d
feat: Group and color sloop doctor; explain the mode line
tuanngo Jun 28, 2026
cc1e467
docs: Sketch the memory/vault design and the status-hook privacy boun…
tuanngo Jun 28, 2026
1ad37c0
docs: Design sloop peek — overlay into a waiting agent without losing…
tuanngo Jun 28, 2026
f5f9922
docs: Move peek design into docs/design and ignore superpowers scratch
tuanngo Jun 28, 2026
09b1c17
docs: Simplify peek signal layer to augment the existing statusline r…
tuanngo Jun 28, 2026
8b19196
feat: Add tmux peek helpers for nested-attach overlay
tuanngo Jun 28, 2026
b56d973
feat: Add sloop peek to overlay a waiting agent without switching scr…
tuanngo Jun 28, 2026
2cf53c1
feat: Show a fleet-wide waiting badge on the status line
tuanngo Jun 28, 2026
dc52f96
docs: Design profiles and named instances for run
tuanngo Jun 28, 2026
0077a9b
feat: Add instance naming and env injection primitives
tuanngo Jun 28, 2026
241bf44
feat: Add launch profiles to global config
tuanngo Jun 28, 2026
b5defb0
feat: Resolve profile and instance tokens for run
tuanngo Jun 28, 2026
be2a577
feat: Wire profiles and named instances into run
tuanngo Jun 28, 2026
b3fa8ab
feat: Parse and display named instances in the fleet view
tuanngo Jun 28, 2026
c159f35
feat: Add sloop profile command to manage run profiles
tuanngo Jun 28, 2026
a679bc4
docs: Document profiles, named instances, and peek
tuanngo Jun 28, 2026
ef04ff2
docs: Clean up design docs to pure design and mark shipped
tuanngo Jun 28, 2026
bf5b132
docs: Prepare v0.1.1 changelog
tuanngo Jun 28, 2026
a6da949
chore: Apply gofmt to test struct alignment
tuanngo Jun 28, 2026
46daa86
fix: Cancel TUI prompts on stdin read error and check marshal error
tuanngo Jun 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ dev-notes.md
_features/

# runtime
*.pid
*.pid
# brainstorming scratch (tooling-specific, not for public repo)
docs/superpowers/
Empty file removed .sloop/skills/.gitkeep
Empty file.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@
All notable changes to Sloop are documented here. This project adheres to
[Semantic Versioning](https://semver.org/).

## v0.1.1 — 2026-06-28

Run more than one agent per repo, peek into a waiting agent without leaving your
screen, and a sharper first-run experience — all on top of v0.1.0.

### Run multiple agents & accounts
- Named instances: `sloop run claude@review` / `-n/--name` runs a second agent of the same tool in one
repo (session `<repo>__tool__instance`); `-N/--new` auto-names the next free slot (`claude·2`…).
- Profiles: save a tool + env once with `sloop profile add|ls|rm` (global `~/.sloop/config.yaml`) and
launch it as `sloop run @<name>` — e.g. a different account via `CLAUDE_CONFIG_DIR`. `--env KEY=VAL`
injects env one-off without a profile (`~`/`$VAR` expanded). The fleet view shows instances as
`tool·instance`.

### Peek (overlay a waiting agent)
- `sloop peek` floats a waiting agent's live pane over your current screen so you can answer it and
drop back without `switch-client` swapping your whole screen; `sloop peek setup` binds a key. Needs
tmux ≥ 3.2. Every status bar gains a fleet-wide `⏳ N waiting` badge.

### Sharper onboarding (init / check / doctor)
- `sloop init` is provider-respecting: it asks about the tools you actually use (Claude-first order),
prompts honestly and skips work that is already done, selects tools per workspace, and no longer
offers to scaffold a provider's folders for it.
- `sloop check` gains more AI-readiness criteria, sourced from each tool's adapter manifest.
- `sloop doctor` groups and colors its output and explains the `mode` line.

## v0.1.0 — first release

The initial public release: the local-first control layer for your AI coding CLIs.
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ picker.
> only touches `status-left`/`status-right` (not your colors/theme). Keep your own bar fully intact with
> `SLOOP_STATUSLINE=0`.

**Don't want to leave your screen?** From inside one agent, **`sloop peek`** floats a *waiting* agent's
live pane over your current work — answer it, close it, and you're exactly where you were (no
`switch-client` that swaps your whole screen). Bind a key with `sloop peek setup`. Needs tmux ≥ 3.2.

**A second agent, or a second account?** `sloop run claude@review` opens another claude in the same
repo (`claude·review` in the fleet); `sloop run claude --new` auto-names the next one (`claude·2`). For a
different account, save a profile once — `sloop profile add sec --tool claude --env CLAUDE_CONFIG_DIR=~/.claude-sec`
— then `sloop run @sec`.

`sloop ls` is the companion view — your registered **workspaces** (running or not) with their live
agents — to launch (`r`), open a shell (`s`), `c` to copy a `cd`, or `Enter` to jump in.

Expand All @@ -145,7 +154,8 @@ agents — to launch (`r`), open a shell (`s`), `c` to copy a `cd`, or `Enter` t
| Command | Alias | Flags (short) | What it does |
|---|---|---|---|
| `init` | — | `-s/--scan`, `-S/--scaffold` | Scaffold `AGENTS.md` + `.sloop/`, deliver pointers, register the workspace. `--scan` pre-fills `AGENTS.md` from the codebase; `--scaffold` creates each tool's standard folders. |
| `run [tool]` | `r` | `-w/--workspace`, `--split`, `-- <args>` | Sync context, then launch a tool (in tmux if present). `--split` runs several side by side; `-w` targets a registered workspace from anywhere. |
| `run [tool]` | `r` | `-n/--name`, `-N/--new`, `--env`, `-w/--workspace`, `--split`, `-- <args>` | Sync context, then launch a tool (in tmux if present). Run a **2nd agent of the same tool** with `tool@instance`, `-n/--name`, or `-N/--new` (auto-named `tool·2`…); a **different account** with a saved `@profile` or one-off `--env KEY=VAL`. `--split` runs several side by side; `-w` targets any registered workspace. |
| `profile add\|ls\|rm` | `prof` | `add --tool`, `add --env` | Save reusable run profiles in `~/.sloop/config.yaml` (e.g. a 2nd account's `CLAUDE_CONFIG_DIR`); launch one with `sloop run @<name>`. |
| `sync [tool]` | `s` | `-a/--all`, `-r/--repair`, `-w/--workspace` | (Re)deliver pointer files + skills symlinks without launching. `--repair` safely moves a foreign file aside (never deletes). |
| `ps [#]` | — | `-f/--watch`, `-n/--interval`, `--waiting`, `--notify`, `--all` | The cross-repo fleet. Reads what each agent is asking and shows answer keys; `<#>` jumps; `-f` live-monitors + alerts. |
| `approve <target>` | — | `--waiting`, `--all`, `--yes` | Send the Yes/Approve answer to waiting agent(s) — one-command approve. |
Expand All @@ -154,6 +164,7 @@ agents — to launch (`r`), open a shell (`s`), `c` to copy a `cd`, or `Enter` t
| `adopt <tmux-session>` | — | `-w/--workspace`, `--as` | Bring an external tmux session (one you started yourself) into the fleet. |
| `restore` | — | `--resume`, `--yes` | Relaunch your recent agents (detached) after a reboot / tmux restart. `--resume` continues each tool's prior conversation. |
| `popup` / `popup setup` | `hud` | `--key` | Open the fleet `ps` as a floating tmux popup / HUD; `setup` binds a key. Needs tmux ≥ 3.2. |
| `peek [agent]` / `peek setup` | `pk` | `--key` | Overlay a waiting agent in a floating popup — answer it and drop back **without switching your whole screen**. No arg → the lone waiting agent or a picker; `setup` binds a key. Needs tmux ≥ 3.2. |
| `statusline setup` | — | — | Show a session's live status (`⚓ repo tool ◆ waiting`) in its tmux status bar. |
| `attach [session]` | `a` | — | Attach to a session by name, or `sloop a` (no name) to pick from the fleet. |
| `skills new\|add <…>` | `sk`, `skill` | `new`→`n`, `add`→`import` | Scaffold or import a reusable skill (shared across every tool). |
Expand Down Expand Up @@ -248,6 +259,8 @@ hooks: # status hooks for `sloop ps`
- [docs/reference/CONFIG.md](docs/reference/CONFIG.md) — the three config layers (local / global / built-in)
- [docs/reference/ADAPTERS.md](docs/reference/ADAPTERS.md) — the provider-aware adapter contract
- [docs/design/run.md](docs/design/run.md) — `sloop run` design: CLI · model · effort resolution
- [docs/design/profiles.md](docs/design/profiles.md) — named instances & profiles: a 2nd agent / 2nd account
- [docs/design/peek.md](docs/design/peek.md) — overlay a waiting agent without leaving your screen
- [docs/design/skills.md](docs/design/skills.md) — skills model, lockfile, registry roadmap
- [docs/design/hooks.md](docs/design/hooks.md) — status hooks today, workflow-hook design for v0.2.0
- [docs/reference/ARCHITECTURE.md](docs/reference/ARCHITECTURE.md) — packages, data flow, internals
Expand Down
81 changes: 75 additions & 6 deletions docs/design/hooks.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# Hooks — status today, portable workflow automation next

AI CLIs expose **hooks**: events that fire at points in a session (per-session, per-turn, per
tool-call) where a command can observe, react, or block. Sloop uses hooks two ways — and keeping the
two cleanly separated is the whole design.
tool-call) where a command can observe, react, or block. Sloop uses hooks three ways — and keeping
them cleanly separated is the whole design:

> **Status hooks** ship today. **Workflow hooks** are a v0.2.0 proposal — this doc is the contract to
> review *before* it's built. Command reference for status hooks: [USAGE.md](../guide/USAGE.md); the install
> mechanism: [ADAPTERS.md §Hook install strategies](../reference/ADAPTERS.md).
1. **Status hooks** (shipped) — observe state for `sloop ps`.
2. **Workflow hooks** (v0.2.0 proposal) — run the user's portable automation.
3. **Context-inject hooks** (proposal) — deliver sloop's portable context / memory into a session at
`SessionStart`, without writing into the tool's own context file.

## Two kinds of hook (don't conflate them)
> **Status hooks** ship today. **Workflow hooks** and **context-inject hooks** are proposals — this doc
> is the contract to review *before* they're built. Command reference for status hooks:
> [USAGE.md](../guide/USAGE.md); the install mechanism:
> [ADAPTERS.md §Hook install strategies](../reference/ADAPTERS.md).

## Status vs. workflow hooks (don't conflate them)

These two write into the *same* provider config, so the bulk of the design is keeping them apart.
(Context-inject hooks live on a different event and are read-only, so they don't share this hazard —
see their own section below.)

| | **Status hooks** (shipped) | **Workflow hooks** (v0.2.0) |
|---|---|---|
Expand Down Expand Up @@ -41,6 +51,28 @@ writes a short-lived marker under `~/.sloop/state` that `sloop ps` prefers over
in the adapter manifest. Auto-install today: **claude, gemini, cursor**; **copilot, codex** are
`print+paste` pending a matcher-aware model (below). See [ADAPTERS.md](../reference/ADAPTERS.md).

### Privacy: status hooks never read your session

This is a deliberate boundary and a promise we make to users. Sloop's status hook emits **one state
word** — `waiting` / `working` / `idle` plus a timestamp — into a local marker file. It does **not**:

- read the prompt or the model's response,
- read file contents or tool inputs,
- make any network call.

Contrast a typical lifecycle bridge (e.g. the `claude-code-warp` plugin), whose `Stop` hook *reads the
session, extracts the last prompt + response, and ships a summary* to an external notification center.
That is a real content-exfiltration surface; sloop's fleet awareness deliberately stays at the
state-enum level, so "sloop knows an agent is idle" never means "sloop read what it was doing."

The wiring is auditable end to end: `sloop hooks print` shows the exact line that gets added, the
command is literally `sloop hooks emit <state>`, it installs into `settings.local.json` (not
committed), the merge is idempotent, and any hand-written ("foreign") hooks in the file are preserved.

The only surface that *does* execute arbitrary code is **workflow hooks** (below) — which is exactly
why they are gated behind a lockfile + checksum + review-before-run, and why the internal status
callback is namespaced as `hooks emit` rather than a bare top-level `hook`.

## Workflow hooks (v0.2.0 proposal)

Turn hooks into a **portable automation library**: pick a hook, sloop installs it into the right
Expand Down Expand Up @@ -94,6 +126,43 @@ runs on a teammate's machine. So, unlike skills, the library needs:
AI tool.
- Each definition declares its target mechanism; sloop installs into that and nowhere else.

## Context-inject hooks — the memory/vault bridge (proposal)

Today sloop delivers portable context by **writing files**: `AGENTS.md` plus per-tool pointers
(`CLAUDE.md`, etc.). That works, but it has two limits: it touches files the provider considers its
own, and it's static — it can't reflect what the workspace has *learned* between sessions.

A `SessionStart` hook is the third delivery channel, and it's the one that unlocks the **memory /
vault** direction (design to live in `docs/design/memory.md`). The pattern is the
Superpowers one: register a single read-only hook that, at session start, prints sloop's relevant
context to stdout — the provider injects that into the session as additional context. Sloop never
rewrites the user's prompt and never edits the tool's `CLAUDE.md`; it speaks through the provider's
**own** `SessionStart` mechanism.

```text
SessionStart → `sloop context emit` → prints relevant vault/AGENTS context → provider injects it
```

Why this is the right shape for memory:

- **Dynamic, not static.** The hook runs each session, so it can surface what was learned/saved since
last time — the static `AGENTS.md` can't.
- **Provider-respecting.** It's the *third* way the user asked about ("write into AGENTS.md, or
CLAUDE.md, or through our hooks") — and the only one that doesn't write into the tool's files.
- **Same trust posture as status hooks.** Injection is **read-only and outbound-only**: sloop emits
context it already owns under `.sloop/`; it does not read the session. No new exfiltration surface.
- **No bundled LLM.** Selection of "relevant" context stays plumbing (recency, the active workspace,
simple matching). Any real retrieval is delegated to the agent — sloop is not the model.

Open design questions specific to this channel (to be settled in `docs/design/memory.md`, not here):

- What "relevant context" means at session start (whole vault vs. a recency/scoped slice) and the
token budget for an injection.
- How memory gets *written* (a `SessionEnd`/`Stop` capture hook? an explicit `sloop remember`?) — the
write path is a separate decision from this read path.
- Per-provider `SessionStart` support + payload shape in the adapter manifest (which CLIs expose it,
and whether non-supporting tools fall back to the file-pointer delivery).

## Open questions (feedback wanted before the build)

- Library distribution: embedded built-ins in this repo first (review via PR, ship with the binary,
Expand Down
114 changes: 114 additions & 0 deletions docs/design/memory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Memory / vault — the 2nd-brain bridge (DRAFT design)

> **Status: skeleton for discussion.** Nothing here is built or decided. This captures *what we want
> to do* and the constraints it must respect, so we can review and argue the shape before writing
> code. The delivery mechanism (a read-only `SessionStart` context-inject hook) is sketched in
> [hooks.md §Context-inject hooks](hooks.md); this doc owns the memory model itself.

## The problem

Portable context today is **static and write-once**: `init`/`sync` write `AGENTS.md` + per-tool
pointers, and that's it. Two gaps follow:

1. **Nothing is learned.** A decision made or a gotcha hit in session A is gone by session B. The user
re-explains the same things to the same (or a different) tool.
2. **Nothing is shared across the fleet.** sloop's wedge is portable context + cross-repo fleet, but
"context" is currently just a file the user maintains by hand — not something the fleet accrues.

The goal: a **2nd brain** that the workspace accrues over time and replays into any tool, any session,
any repo — without sloop becoming the model.

## Goals

- **Capture** durable facts/decisions/gotchas from real sessions (or explicit user input) into a local
store.
- **Replay** the relevant slice back into a fresh session automatically, via the provider's own
`SessionStart` mechanism (no rewriting prompts, no editing the tool's `CLAUDE.md`).
- **Portable** across the five+ CLIs and across repos — same store, any tool reads it.
- **Provider-respecting and private by construction** — same posture as status hooks (read-only,
outbound-only, local; see hooks.md privacy note).

## Non-goals (bright lines)

- **No bundled LLM / RAG / embeddings / vector DB.** sloop is plumbing. "Relevance" is mechanical
(recency, active workspace, simple matching), and any real semantic retrieval is delegated to the
agent — *it* is the LLM. The moment we'd reach for embeddings, we stop and hand the job to the tool.
- **No silent capture of session content.** Writing to memory is an explicit, visible act (see the
write-path question) — never a hook that quietly scrapes prompts/responses.
- **Not a knowledge base / wiki / sync service.** The vault is local notes the fleet replays, not a
hosted product.

## Shape (two paths, decided separately)

Memory splits into a **read path** (replay) and a **write path** (capture). They're independent
decisions; we can ship the read path against a hand-written vault long before automating capture.

### Read path — replay (closest to ready)

```text
SessionStart → `sloop context emit` → selects relevant vault slice → provider injects it as context
```

- Read-only, outbound-only. Emits content sloop already owns under `.sloop/`. No session reading.
- Selection is plumbing: recency + active workspace + simple matching, under a token budget.
- Falls back to file-pointer delivery for tools that don't expose `SessionStart`.

### Write path — capture (more open)

How does a fact *get into* the vault? Candidates, not yet chosen:

- **Explicit** — `sloop remember "<fact>"` (and/or a `/remember`-style provider command). Highest
trust, zero magic, user-curated. Likely the v1.
- **Prompted capture** — a `SessionEnd`/`Stop` hook that *asks* the user "save anything from this
session?" rather than auto-scraping. Keeps the human in the loop.
- **Agent-authored** — the tool itself writes a note via a skill/command when it learns something.
Delegates the "what's worth remembering" judgment to the model (consistent with the no-LLM line).

We deliberately **avoid** an auto-`Stop`-hook that reads and stores session content silently — that
would cross the privacy line we drew for status hooks.

## Storage model (sketch)

- Lives under `.sloop/vault/` (already scaffolded by `init`, already in `.sloop/.gitignore` as
personal/not-shared by default).
- Plain files (Markdown, one fact per file?) so it's greppable, diffable, and editable by hand — and
so the agent can read/write it with its normal file tools. Mirrors how *this* assistant's own
`MEMORY.md` index + per-fact files work; that pattern is a candidate to copy outright.
- **Open:** per-fact files + an index vs. a single file; frontmatter schema (type, scope, created);
personal (gitignored) vs. team-shared (committed) tiers; per-workspace vs. a global cross-repo vault
(the cross-repo wedge probably wants *both*: a global brain + a per-workspace overlay).

## Open questions (the things to argue in review)

- **Relevance without a model.** What's the actual selection rule for "what to inject at SessionStart"?
Whole vault (simple, but blows the token budget fast) vs. a recency/scope slice vs. tag-matching on
the workspace. Where's the budget cap?
- **Write trigger.** Explicit `sloop remember` first, or invest in prompted capture early? What's the
smallest thing that's genuinely useful?
- **Scope & sharing.** Per-workspace vs. global brain; personal (gitignored) vs. committed/team. How do
the two layers compose at injection time?
- **Cross-repo replay.** The wedge says context should follow you across repos — does a global vault
inject into *every* workspace, or only on demand? How is "this fact is about repo X" expressed?
- **Provider coverage.** Which CLIs expose `SessionStart` (and an injectable payload)? Manifest field +
fallback for those that don't.
- **De-dup / decay.** How do stale or contradicted facts get pruned? (Our own memory rules — "update
the existing file, delete what's wrong" — are a candidate policy.)
- **Interop.** Should sloop's vault read/emit alongside a tool's *native* memory (e.g. a provider's own
memory feature) rather than compete with it?

## Phasing (proposal)

1. **Read path on a hand-written vault.** `sloop context emit` + one provider's `SessionStart` wiring;
user maintains `.sloop/vault/` by hand. Proves the injection channel end to end.
2. **Explicit capture.** `sloop remember` writes a fact; emit picks it up next session.
3. **Selection + scope.** Recency/scope slicing, token budget, per-workspace vs. global layering.
4. **Cross-repo brain.** Global vault that replays into any workspace; team-shared tier.

(Each phase is independently shippable and independently reviewable. We are not committing to past
phase 1 until phase 1 earns it.)

## Related

- [hooks.md](hooks.md) — the three hook uses; the `SessionStart` context-inject channel this doc rides
on, and the privacy posture it inherits.
- Product direction: portable context + cross-repo fleet is the wedge; keep LLM out of the core.
Loading