Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0acdb1c
feat: catalog herdr agent integrations
codejunction Oct 3, 2026
b23afb6
feat: add agent lifecycle domain model
codejunction Oct 3, 2026
13a5fb9
expanded agent enhancement doc and task
codejunction Oct 4, 2026
c2513af
feat(agents): server-owned lifecycle, report api, waits, context store
claude Oct 4, 2026
05ded02
feat(skill): teach agents shared context workflow
claude Oct 4, 2026
d63b246
docs(agents): lifecycle, report api, waits, context cli
claude Oct 4, 2026
7428629
feat(integrations): lifecycle hooks for claude, gemini, cursor, copil…
claude Oct 4, 2026
2b70bf0
feat(agents): codex and claude lifecycle from their own logs
claude Oct 4, 2026
0e3f7ca
feat(agents): resume stored agent sessions after restart
claude Oct 4, 2026
f82b6e2
docs(readme): agent resume setting row
claude Oct 4, 2026
31260ab
feat(integrations): codex hooks, session hooks for qwen, qoder, droid…
claude Oct 4, 2026
1493df9
feat(integrations): kimi, mastracode, kilo, grok, antigravity
claude Oct 4, 2026
3e6ce1c
feat(integrations): letta session hook, hermes plugin
claude Oct 4, 2026
e37d03e
feat(integrations): pi and omp extensions
claude Oct 4, 2026
dfc69f3
feat(integrations): claude, codex, gemini, devin as supported set
claude Oct 4, 2026
10eaae7
feat(agents): attention queue and project rollups
claude Oct 4, 2026
1f547e9
feat(agents): sd agent explain diagnostics
claude Oct 4, 2026
b03feb5
feat(agents): prompt --wait, rename, event stream
claude Oct 4, 2026
5ccfa42
feat(agents): native cli flags for launch, spawn, resume
claude Oct 4, 2026
8f35e4d
feat(agents): native slash commands per agent
claude Oct 4, 2026
5264079
feat(context): context page
claude Oct 4, 2026
c474857
feat(agents): versioned detection rules with local overrides
claude Oct 4, 2026
c5937e1
feat(agents): sd switch, message action, skill update
claude Oct 4, 2026
3187b46
feat(context): agents extract their own facts on demand
claude Oct 4, 2026
f0c3842
docs(integrations): support matrix with verification source
claude Oct 4, 2026
d473cd3
fix(agents): heuristic verdict replaces the previous one
claude Oct 4, 2026
c516ac9
docs(task): record 0.0.7rc1 release
claude Oct 4, 2026
2d991fd
feat(context): deterministic capture of agent commands, tests, edits,…
claude Oct 4, 2026
c3178d1
feat(agents): devin cli commands and hooks cross-checked from web sou…
claude Oct 4, 2026
fcdb1e5
docs(task): tick ci matrix and docs items
claude Oct 4, 2026
3886969
feat(context): smart recall via agent small models, no embeddings
claude Oct 4, 2026
e4b18eb
docs(task): claude verified with real cli; prepare rc2
claude Oct 4, 2026
f9072ad
docs(task): record 0.0.7rc2 release
claude Oct 4, 2026
7f144ce
feat(ui): declutter sidebar footer
claude Oct 4, 2026
4a27bc6
feat(context): human friendly context page, pick agent and model for …
claude Oct 4, 2026
0504f11
docs(task): record 0.0.7rc3 release
claude Oct 4, 2026
f9453f5
feat(context): sd init sets up .shelldeck in a project
claude Oct 4, 2026
fdc479f
docs(readme): refresh screenshots, one actions menu per agent row
claude Oct 4, 2026
a66f521
docs(agents): restructure enhancement doc around what shipped
claude Oct 4, 2026
5150f90
chore(release): 0.0.7
claude Oct 4, 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
Prev Previous commit
Next Next commit
feat(agents): devin cli commands and hooks cross-checked from web sou…
…rces

- devin slash commands expanded and verified; exec shell tool captured
- test guards devin hook events (devin rejects unknown ones)
- update task.md
  • Loading branch information
claude committed Oct 4, 2026
commit c3178d1ce318dd672c4f7fb74cf971464978c195
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ All notable changes to shelldeck are listed here. The format follows [Keep a Cha
- The support matrix (exact state, resume, and what each format was checked against) is in [docs/agent-integrations.md](docs/agent-integrations.md#support-matrix).
- Deterministic capture: agent tool calls (command + success, edited file) from hooks and people's shell commands become context events. Test runs set the project's Tests line, failures (not look-ups like grep) set Last error, and each agent run writes `.shelldeck/sessions/<id>.md` when it ends.
- Fixed: a redacted value could corrupt a stored context event (secrets are now redacted per value before serializing).
- Devin CLI: commands and flags cross-checked from web sources (slash commands `/compact /clear /new /model /context /resume /plan /revert /exit`, shell tool `exec` captured); its hooks are limited to the events Devin accepts.
- Hand-off files include a context snapshot, and the installed agent skill teaches the context workflow.

## [0.0.6] - 2026-10-01
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ uv tool install --force -e . # global sd/shelldeck from this checkout (th
- **Deterministic capture.** `hook.activity()` adds `{command, ok}` or `{file, change}` to tool-finished reports (never output or contents), validated by `agent_state.parse_activity`. The server's `_capture()` runs `context.record_activity` / `start_session` / `end_session` on a thread for the terminal's project; the context session id is `<terminal>.<generation>` (`_ctx_session`). `TEST_CMD` sets the Tests line, `LOOKUP_CMD` failures (grep etc.) aren't errors, and `end_session` writes `.shelldeck/sessions/<id>.md`. People's shell commands (`_record_command`, only when no agent runs there) are captured too. `record_event` redacts per value (`_payload`).
- **Fact extraction** is done by the agents, never by a model in shelldeck: `POST /api/sessions/{id}/extract` types `EXTRACT_PROMPT` (short; tells the agent that dedup/redaction are server-side so it skips reading memory; `sd remember` takes several facts). On demand only, refused while working/blocked.
- `shelldeck/detection.py` + `agent_detection/default.toml`: screen rules for the heuristic (`_next_state`, explain). `load(agent)` merges a local override (`<config>/agent-detection/<agent>.toml`: replace by id, `disable`, add), cached by mtime; an invalid override is ignored and `Manifest.error` says why. `match()` picks the rule matching latest on screen. `agents.QUESTION` stays for sub-agent question forwarding; `QUESTION_RE` in app.js mirrors the bundled phrases.
- `shelldeck/agent_commands.py`: `COMMANDS` maps shelldeck actions to each agent's own slash commands (claude from its cli.js, codex from slash_command.rs, gemini from docs/reference/commands.md; devin `VERIFIED = False` until checked on a real install). `POST /api/sessions/{id}/agent-command` types it, refusing blocked/working agents unless `force`; arguments must match `SAFE_VALUE`.
- `shelldeck/agent_commands.py`: `COMMANDS` maps shelldeck actions to each agent's own slash commands (claude from its cli.js, codex from slash_command.rs, gemini from docs/reference/commands.md; devin from web-search quotes of its docs plus other projects' integrations; Devin rejects unknown hook events, so keep its `hook.EVENTS` within its documented list). `POST /api/sessions/{id}/agent-command` types it, refusing blocked/working agents unless `force`; arguments must match `SAFE_VALUE`.
- `shelldeck/context.py`: persistent agent context in `<config>/context.db` (separate from shelldeck.db; FTS5 `search` table with a LIKE fallback). Projects are keyed by resolved folder (the deepest shelldeck project containing cwd, else the git top level). Everything stored goes through `redact()`; `SENSITIVE_FILE` paths are never referenced. Knowledge is de-duplicated per project by `_norm` and never merged across projects. `check_stale` re-hashes `source_references`. `project_context` returns a `ContextPackage` dict plus budgeted `text`. `project_files` writes STATE/TASK/MEMORY/DECISIONS.md (server runs it on a thread via `_project_later`). Server endpoints are `/api/context*`, wrapped by `_ctx` (sqlite errors -> 503 `context_unavailable`, never a crash). `_handoff_files` appends `context.snapshot`.
- `shelldeck/team.py`: agent teams.
- `tier()`/`pick_model()`: `--model auto|small|medium|large` maps onto the agent's own `models()` by regex (medium = its default).
Expand Down
14 changes: 8 additions & 6 deletions docs/agent-integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ manual check is still on the release checklist.
| claude | priority | hook | yes | yes | Claude Code 2.1.289 (bundle + `--help`) |
| codex | priority | hook | yes | yes | openai/codex source (hooks, slash commands) |
| gemini | priority | hook | yes | yes | gemini-cli docs (hooks, commands, sessions) |
| devin | priority | hook | yes | yes | herdr installer only; Devin CLI not checked (devin.ai blocked) |
| devin | priority | hook | yes | yes | Devin CLI docs via web search + other projects' integrations; CLI not run (devin.ai blocked) |
| copilot | later | hook | yes | yes | dotpals/herdr formats; config files only |
| cursor | later | hook | yes | yes | dotpals/herdr formats; config files only |
| opencode | later | plugin | yes | yes | dotpals/herdr formats; config files only |
Expand Down Expand Up @@ -91,6 +91,8 @@ flags (`team.launch_line`):
| Gemini CLI | `-m` | `-i "prompt"` | none: hooks only from `settings.json` (install) | `gemini --resume <id>` |
| Devin CLI | `--model` | `-- "prompt"` | none: hooks only from `config.json` (install), plus `sessions.db` | `devin --resume <id>` |

Devin's flags (`-- "prompt"`, `--model`, `-r/--resume`, `-c/--continue`, `-p`) and hook events (`SessionStart`, `UserPromptSubmit`, `Pre/PostToolUse`, `PermissionRequest`, `Stop`, `PostCompaction`, `SessionEnd`) were cross-checked the same way. Devin rejects its whole hooks block when it holds an unknown event, so shelldeck installs only events from that list (a test guards it). Its shell tool is `exec`.

A prompt that is longer, or isn't plain words, is written to `.shelldeck/prompts/<id>.md`. The agent is then asked to
read that file, so no shell ever sees quotes or `$`.

Expand All @@ -101,22 +103,22 @@ three, the flags come from their docs as used by dotpals and herdr.

`sd agent cmd TERMINAL ACTION [ARG]` (and the *Command…* menu on the AI agents page) types the agent's own command:

| Action | Claude Code | Codex | Gemini CLI | Devin CLI (unverified) |
| Action | Claude Code | Codex | Gemini CLI | Devin CLI |
| --- | --- | --- | --- | --- |
| compact | `/compact` | `/compact` | `/compress` | `/compact` |
| clear / new | `/clear` | `/clear` / `/new` | `/clear` | `/clear` |
| model | `/model` | `/model` | `/model` | `/model` |
| status | `/status` | `/status` | `/stats` | – |
| resume | `/resume` | `/resume` | `/resume` | – |
| review, init, export, hooks, permissions, plan | yes | yes (+ `/diff`, `/rename`) | init, hooks, permissions, plan, `/memory show`, `/rewind` | – |
| status | `/status` | `/status` | `/stats` | `/context` |
| resume | `/resume` | `/resume` | `/resume` | `/resume` |
| review, init, export, hooks, permissions, plan | yes | yes (+ `/diff`, `/rename`) | init, hooks, permissions, plan, `/memory show`, `/rewind` | plan, `/revert` (rewind), `/new` |
| quit | `/exit` | `/quit` | `/quit` | `/exit` |

Sources:

- Claude: the command names in Claude Code 2.1.289's bundle.
- Codex: `codex-rs/tui/src/slash_command.rs`.
- Gemini: `docs/reference/commands.md`.
- Devin's list is a guess until the Devin CLI can be installed and checked.
- Devin's list comes from the Devin CLI docs as quoted by web search, plus other projects' Devin integrations (docs.devin.ai and the CLI itself are blocked from this build box).

A command is refused while the agent is blocked (it would answer the question) or working, unless `--force`.
`sd agent cmd claude --list` shows an agent's commands.
Expand Down
8 changes: 7 additions & 1 deletion docs/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
checked in a browser. Codex hooks gained PreToolUse/PostToolUse/
PermissionRequest/PreCompact (from codex-rs/hooks); Gemini resume confirmed
in its docs.
- [ ] Devin CLI: install and verify its commands, flags and hooks. The
- [~] Devin CLI: commands, flags and hooks cross-checked from web sources; running the real CLI is still pending. The
environment blocks devin.ai (needs devin.ai / *.devin.ai allowed in the
cloud environment's network settings).
- **2026-10-04 — Task 5.8 (UI) complete:** a *Context* view (sidebar and
Expand Down Expand Up @@ -173,6 +173,12 @@
output, contents and sensitive files are never stored. Fixed a redaction bug
that could corrupt stored event JSON. Checked live (fake agent, hook events,
exit -> session file).
- **2026-10-04 — Devin CLI cross-checked from web sources (user request):**
search results quoting the Devin docs and other projects' Devin integrations
agree with shelldeck's flags (`-- "prompt"`, `--model`, `-r/--resume`), config
path and hook events. Devin rejects unknown hook events, so a test now guards
the installed set. Added its shell tool name `exec` for capture, and expanded
and verified its slash commands. Running the real CLI is still blocked.
- **2026-10-04 — Docs:** README, CHANGELOG (Unreleased), CLAUDE.md,
`docs/agent-automation.md` and `docs/agent-report.schema.json` describe the
lifecycle, report API, waits and context commands.
Expand Down
8 changes: 5 additions & 3 deletions shelldeck/agent_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
claude built-in command names in Claude Code 2.1.289's cli.js
codex codex-rs/tui/src/slash_command.rs (openai/codex)
gemini docs/reference/commands.md (google-gemini/gemini-cli)
devin ponytail: unverified (docs.devin.ai unreachable from the build box); marked `verified: False`
devin Devin CLI docs as quoted by web search (commands & flags, essential commands) and other projects' Devin
integrations; docs.devin.ai itself and the CLI were unreachable from the build box
"""

import re
Expand Down Expand Up @@ -42,9 +43,10 @@
"gemini": {"compact": "/compress", "clear": "/clear", "new": "/clear", "model": "/model", "status": "/stats", "resume": "/resume",
"init": "/init", "memory": "/memory show", "hooks": "/hooks", "permissions": "/permissions", "plan": "/plan",
"rewind": "/rewind", "quit": "/quit"},
"devin": {"compact": "/compact", "clear": "/clear", "model": "/model", "quit": "/exit"},
"devin": {"compact": "/compact", "clear": "/clear", "new": "/new", "model": "/model", "status": "/context", "resume": "/resume",
"plan": "/plan", "rewind": "/revert", "quit": "/exit"},
}
VERIFIED = {"claude": True, "codex": True, "gemini": True, "devin": False}
VERIFIED = {"claude": True, "codex": True, "gemini": True, "devin": True}
SAFE_VALUE = re.compile(r"[\w.:/@+-]{1,80}") # an argument typed after the command: one plain word


Expand Down
5 changes: 3 additions & 2 deletions shelldeck/hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"qwen": {"SessionStart": SESSION},
"qodercli": {"SessionStart": SESSION},
"droid": {"SessionStart": SESSION},
# Devin's hooks are Claude-shaped; herdr reports only its session from them, shelldeck also its state
# Devin's hooks are Claude-shaped (events per its hooks docs). Devin rejects the whole hooks block if it holds an
# unknown event (Notification, PreCompact, ...), so only these may be installed; its shell tool is `exec`
"devin": {"SessionStart": IDLE, "UserPromptSubmit": WORKING, "PreToolUse": WORKING, "PostToolUse": WORKING,
"PermissionRequest": BLOCKED, "Stop": DONE, "SessionEnd": None},
"kimi": {"SessionStart": SESSION, "UserPromptSubmit": WORKING, "PreToolUse": WORKING, "PostToolUse": WORKING,
Expand Down Expand Up @@ -98,7 +99,7 @@ def state_for(agent: str, event: dict, forced: str | None = None) -> tuple[str |
# tool-finished events whose payload names the tool and its input (Claude-shaped; Gemini's AfterTool; Copilot's
# toolName/toolArgs). Only the command or the edited path leaves the agent: never output or file contents.
AFTER_TOOL = {"PostToolUse": True, "PostToolUseFailure": False, "AfterTool": None, "postToolUse": True, "postToolUseFailure": False}
SHELL_TOOLS = {"bash", "shell", "exec_command", "local_shell", "run_shell_command", "powershell", "run_terminal_cmd", "execute"}
SHELL_TOOLS = {"bash", "shell", "exec", "exec_command", "local_shell", "run_shell_command", "powershell", "run_terminal_cmd", "execute"}
EDIT_TOOLS = {"edit", "write", "multiedit", "notebookedit", "write_file", "replace", "apply_patch", "create", "str_replace_editor"}


Expand Down
10 changes: 10 additions & 0 deletions tests/test_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,13 @@ def test_hook_activity_from_finished_tools():
codex = hook.report("codex", {"hook_event_name": "PostToolUse", "tool_name": "shell", "tool_input": {"command": ["cargo", "test"]}})
assert codex["activity"]["command"] == "cargo test"
assert "activity" not in hook.report("claude", {"hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": {"command": "ls"}})


DEVIN_EVENTS = {"PreToolUse", "PostToolUse", "PermissionRequest", "UserPromptSubmit", "Stop", "PostCompaction", "SessionStart", "SessionEnd"}


def test_devin_installs_only_events_devin_accepts():
# Devin refuses its whole hooks block when one event is unknown (e.g. Claude's Notification or PreCompact)
assert set(integrations.INSTALLERS["devin"].events()) <= DEVIN_EVENTS
act = hook.report("devin", {"hook_event_name": "PostToolUse", "tool_name": "exec", "tool_input": {"command": "pytest"}})
assert act["activity"] == {"command": "pytest", "ok": True}
2 changes: 1 addition & 1 deletion tests/test_shelldeck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ def test_native_agent_commands(client, monkeypatch):
("claude", "compact", "x", "no_argument"), ("claude", "model", "a; rm -rf", "invalid_argument")):
with pytest.raises(ValueError, match=code):
agent_commands.line(agent, action, arg)
assert all(not c["verified"] for c in agent_commands.catalog("devin"))
assert agent_commands.line("devin", "rewind") == "/revert" and agent_commands.line("devin", "status") == "/context"
assert {c["action"] for c in client.get("/api/agent-commands/claude").json()["commands"]} >= {"compact", "model", "resume"}
typed = []

Expand Down