Harmonize your agent workforce.
Ragtime is the operating system for agent orchestration — a programmable runtime that sits between you and your AI coding agents, giving you live visibility, dynamic control, and a shared filesystem that agents can read and write as naturally as the terminal.
I use multiple agent harnesses and kept rebuilding the same thing: a dynamic context injection layer that replaces static AGENTS.md files with something context-sensitive. Ragtime breaks that out into a standalone tool that works across agents.
Ragtime is organized around three core systems:
- The Score — the Starlark rule engine and FUSE filesystem working together. Rules declare directory structures, respond to filesystem events, and inject context, approve tools, or coordinate agents — all in a few lines of YAML + Starlark. The filesystem is the score; agents read and write it like sheet music.
- The Bridge — the hook integration layer. Every agent event (tool use, permission requests, session start, stop) flows through
rt hook, which evaluates The Score's rules and returns responses within the agent's hook timeout. - The Ensemble — the shell session system.
rt shlaunches shells and agents with full ragtime integration, correlating PTY output with hook events so every player is tracked and in sync.
Beyond these, ragtime provides:
- Session indexing — every agent session is chunked and indexed for semantic search, so agents (and you) can find relevant past work across any harness
- Live dashboards — real-time event feed, session tracking, and interactive modals for tool approval, available as both a terminal TUI (
rt tui) and a PWA web UI - Statusline telemetry — record Claude Code cost and context window usage per session
- Hook test mode — develop and debug rules locally without running an agent
flowchart TB
Agent["Agent\n(Claude Code / Gemini CLI)"]
subgraph Bridge["The Bridge — hook integration"]
Hook["rt hook"]
SL["rt statusline"]
end
subgraph Daemon["ragtime daemon"]
Rules["Rule Engine\n(Starlark / YAML)"]
Sessions["Session Manager"]
RAG["RAG Indexer"]
Bus["Event Bus"]
DB[(SQLite)]
Sessions --> RAG
end
subgraph Score["The Score — FUSE + rules"]
Mount["rt mount"]
FS["~/.ragtime/fs/\ntasks · messages · active · agents"]
Mount --> FS
end
subgraph Dashboards["Dashboards"]
TUI["rt tui"]
PWA["PWA"]
end
subgraph Ensemble["The Ensemble — shell sessions"]
Sh["rt sh"]
PTY["correlated PTY session"]
Sh --> PTY
end
Agent -->|"hook event"| Hook
Agent -->|"statusLine"| SL
Hook --> Daemon
SL --> Daemon
Daemon -->|"hook response"| Hook
Rules --> Mount
Bus --> TUI & PWA
PTY -->|"hook events"| Daemon
The daemon runs as a background process communicating over a Unix socket. Hook events flow in through The Bridge, get evaluated against The Score's rules, and responses flow back — all within the agent's hook timeout window. The Ensemble correlates shell and agent sessions so every event is traceable to its source.
# Build
go build -o rt ./cmd/ragtime
codesign --sign "Apple Development: Your Name" rt
cp rt /usr/local/bin/rt
# Start the daemon
rt start
# Open the live terminal dashboard
rt tui
# Or open the PWA web UI in your browser (rt start prints the URL)
# Mount the FUSE filesystem
rt mount
ls ~/.ragtime/fs/active/ # live session summariesAdd to your Claude Code settings (.claude/settings.local.json):
{
"hooks": {
"PreToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event pre-tool-use" }] }],
"PostToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event post-tool-use" }] }],
"PermissionRequest": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event permission-request" }] }],
"Stop": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event stop" }] }],
"SubagentStop": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event subagent-stop" }] }],
"Notification": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event notification" }] }],
"SessionStart": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event session-start" }] }],
"UserPromptSubmit": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "rt hook --agent claude --event user-prompt-submit" }] }]
},
"statusLine": {
"type": "command",
"command": "rt statusline --agent claude"
}
}The statusLine entry records per-turn cost, token usage, and context window percentage to SQLite. Note the camelCase key — statusLine, not statusline.
Rules live in ~/.ragtime/rules/ (global) or .ragtime/rules/ (per-project) as YAML files:
# .ragtime/rules/rag-context.yaml
name: inject-project-docs
match:
event: pre-tool-use
tool: "Read|Write|Edit"
actions:
- type: rag-search
collections: [project-docs]
query_from: tool_input.file_path
top_k: 3For dynamic logic, use Starlark:
# .ragtime/rules/review-bash.yaml
name: review-bash-commands
match:
event: pre-tool-use
tool: Bash
actions:
- type: starlark
script: |
cmd = event.tool_input.get("command", "")
if "rm " in cmd or "drop " in cmd.lower():
answer = response.prompt(
text="## Destructive Command\n\n```bash\n" + cmd + "\n```\n\nAllow this?",
type="approve_deny_cancel",
default="deny",
timeout=15,
)
if answer == "approve":
response.approve()
else:
response.deny("blocked by review rule")For permission-level control using Claude's built-in permission system:
# ~/.ragtime/rules/review-permission.yaml
name: review-permission
match:
event: permission-request
actions:
- type: starlark
script: |
tool = event.tool_name
cmd = event.tool_input.get("command", "")
path = event.tool_input.get("file_path", "")
detail = cmd if cmd else path
if detail:
text = "## Permission Request\n\n**Tool:** `" + tool + "`\n\n```\n" + detail + "\n```\n\nAllow this?"
else:
text = "## Permission Request\n\n**Tool:** `" + tool + "`\n\nAllow this?"
if tui.connected():
answer = response.prompt(
text=text,
type="approve_deny_cancel",
default="approve",
timeout=5,
)
if answer == "approve":
response.approve()
elif answer == "deny":
response.deny("denied via TUI review")
# If no TUI, fall through to agent's default behavior# Search past agent sessions
rt search sessions "how did we implement the auth middleware"
# List available collections
rt search --collections# Synthetic event with specific rule files
rt hook --test --tool Bash --input '{"command":"rm -rf /tmp"}' \
--rule rules/review-bash.yaml --verbose
# Test multiple rules together
rt hook --test --tool Read --input '{"file_path":"src/main.go"}' \
--rule rules/rag-context.yaml --rule rules/log-all.yaml
# Interactive TUI modal testing
rt hook --test --tui --tool Bash --input '{"command":"docker stop app"}' \
--rule rules/review-bash.yamlrt mount exposes a live read-only (with writable exceptions) filesystem at ~/.ragtime/fs/:
~/.ragtime/fs/
├── active/
│ └── <session-id>/
│ ├── summary.txt # cost, tokens, context window %, model
│ └── status.json # full session state as JSON
├── agents/
│ └── <agent-id>/
│ ├── output.log # live PTY output (for rt sh sessions)
│ ├── input # writable — send text to the agent
│ └── notes/ # writable per-session notes
├── sessions/ # session history
├── shells/ # running rt sh processes
├── collections/ # RAG index listings
├── tasks/ # task workflow (declared by builtin:task-state rule)
│ ├── inbox/ # writable — create tasks here
│ ├── pending/ # writable
│ ├── active/ # writable
│ ├── blocked/ # writable
│ ├── done/ # writable
│ └── failed/ # writable
└── messages/ # inter-agent message bus (declared by builtin:message-bus rule)
└── <session-id>/
├── inbox/ # writable — deliver messages here
└── read/
active/ is populated from recent statusline events so it survives daemon restarts. Each session directory shows the current model, cumulative cost, token counts, and context window percentage.
The tasks/ and messages/ directories are not hardcoded in Go — they are declared by builtin Starlark rules via vfs: blocks. Any rule can create new directories in the filesystem this way. See docs/GETTING_STARTED.md for a complete walkthrough.
rt mount # mount at ~/.ragtime/fs/
rt umount # unmount
cat ~/.ragtime/fs/active/*/summary.txt # check all active sessions
# Task workflow via filesystem
echo '{"title":"Fix login bug","priority":"high"}' > ~/.ragtime/fs/tasks/inbox/fix-login.json
mv ~/.ragtime/fs/tasks/inbox/fix-login.json ~/.ragtime/fs/tasks/active/fix-login.json
mv ~/.ragtime/fs/tasks/active/fix-login.json ~/.ragtime/fs/tasks/done/fix-login.jsonrt sh launches a shell (or wraps a command) with full ragtime integration:
rt sh # interactive shell
rt sh new -- claude # launch agent with correlation
rt sh new --name my-session # named sessionShells launched via rt sh set RAGTIME_SOCKET and RAGTIME_SHELL_ID so hook events and statusline telemetry are automatically correlated with the PTY session. The shell's output is captured and visible in active/<session>/output.log via FUSE.
Rules have access to the full event, response helpers, RAG search, TUI state, and interactive prompts. See docs/starlark-api.md for the complete reference.
Key capabilities:
| API | Description |
|---|---|
event.* |
Read event fields (agent, tool_name, tool_input, etc.) |
response.approve/deny/ask() |
Control tool permission |
response.inject_context(text) |
Add context visible to the agent |
response.prompt(text, type, ...) |
Interactive TUI modal with timeout |
response.set_output(key, value) |
Set raw agent output fields |
response.agent |
Current agent platform name |
rag.search(collection, query) |
Search indexed documents |
tui.connected() |
Check if a dashboard (TUI or PWA) is connected |
inject_input([...]) |
Send keystrokes to terminal multiplexer |
log(...) |
Write to daemon log |
| Component | Description |
|---|---|
rt start/stop/restart |
Daemon lifecycle management |
rt hook |
Agent hook handler (stdin/stdout JSON relay) |
rt hook --test |
Local rule testing without daemon |
rt statusline |
Record Claude Code statusLine telemetry to SQLite |
rt tui |
Live terminal dashboard (TUI) |
| PWA web UI | Browser-based dashboard for tracking and approvals (served by the daemon) |
rt mount / rt umount |
Mount/unmount the FUSE filesystem |
rt sh |
Launch a shell or command with ragtime integration |
rt search |
RAG collection search |
rt index |
Index management |
rt add |
Add content to collections |
rt status |
Daemon status |
rt rules |
List loaded rules |
rt session |
Session management |
- Getting Started — installation, setup, and task system walkthrough
- Starlark API Reference — complete rule scripting API
- Design Document — architecture and design decisions
go build -o rt ./cmd/ragtime
codesign --sign "Apple Development: Your Name (TEAMID)" rtRequires Go 1.21+. Single binary, no external dependencies at runtime (embeddings require a local Ollama instance for RAG features). The FUSE filesystem requires fuse-t on macOS.
Ragtime is in active early development — functional but not yet stable.
| Area | Status | Notes |
|---|---|---|
| Daemon lifecycle | Working | rt start/stop/restart, PID tracking, Unix socket IPC |
| Hook relay | Working | stdin/stdout JSON relay for Claude Code hooks; all event types supported |
| Rule engine | Working | YAML rule matching by event type, tool name, and glob patterns |
| Starlark scripting | Working | Full scripting in rule actions — conditionals, event inspection, response control |
| RAG indexing | Working | Ollama-backed embeddings, per-collection chunking and search |
| Session indexing | Working | Automatic session capture, chunked and indexed for cross-session search |
| TUI dashboard | Working | Live event feed, session panel, interaction modals (approve/deny/cancel), uptime ticker |
| TUI search | Working | Press / to run semantic search against the sessions collection from within the TUI |
| PWA web UI | Working | Browser-based dashboard for session tracking and tool approvals |
| Hook test mode | Working | rt hook --test for local rule development without a daemon |
| Permission requests | Working | PermissionRequest event support with TUI-based approval flow and auto-approve countdown |
| Markdown rendering | Working | Glamour-based rendering in TUI modals |
| Hot reload | Working | Rule changes take effect immediately without daemon restart |
| Session summary on connect | Working | session-summary rule injects recent session context on SessionStart via RAG search |
| Statusline telemetry | Working | rt statusline records cost, tokens, model, and context window % per turn to SQLite |
| FUSE filesystem | Working | rt mount exposes live session data, agent PTY output, and notes as browsable files |
| Shell sessions | Working | rt sh launches correlated shell/agent sessions; PTY output captured in FUSE |
| Active session dashboard | Working | active/ FUSE dir shows per-session summary with cost/context window from DB |
| Hook/shell correlation | Working | Hook events from rt sh sessions carry shell ID for cross-correlation |
| VFS namespaces | Working | Rules declare filesystem directories via vfs: blocks; Go layer is fully generic |
| Task workflow | Working | tasks/ FUSE dirs (inbox/pending/active/blocked/done/failed) backed by SQLite via Starlark rule |
| Message bus | Working | messages/<session-id>/inbox/ delivers nudges to live agent sessions |
| Multi-agent support | Partial | Hook relay works with any agent; Starlark response.agent exposes platform name. Session capture tested with Claude Code only |
- Project-scoped search — filter
rt search sessionsby project/repo to reduce noise - Agent note-taking —
rt noteorrt addfrom Starlark to leave breadcrumbs for future sessions - Curated session summaries — compress session chunks to save index space
- Rule hit analytics — see which rules fire most often to help tune configurations
- More example rules and cookbook patterns
- Stability, error handling, and documentation polish
Apache License 2.0 — see LICENSE for details.