Docs · Capabilities

Tools

Fulcrum's agent has roughly 47 tools that run on your machine, not in the model. The model picks which tool to call; Fulcrum runs it locally and streams the result back. Read-only tools (Read, Grep, Ls, Glob, LSP) run unattended; write tools (Edit, Write, Bash, NotebookEdit) trigger an approval prompt unless Ctrl+Y auto-approve is on.

Every tool below is a real, shipping class in the binary. Cards are tagged Auto when they run without prompting and Asks first when they go through ctx.approve before running.

File I/O

Reads run unattended; every write goes through ctx.approve so you see the diff before it lands.

ReadAuto

Read a text file from disk and return it with cat -n style line numbers.

  • Output is six-digit line number, tab, content — the model navigates by line number when it hands old_string back to Edit.
  • Refuses files over 10 MB and binary files (null-byte sniff on the first 8 KB).
  • Honours offset (1-indexed) and limit so the agent can page large files instead of truncating.
WriteAsks first

Write or overwrite a file. Creates parent directories. Atomic via temp-file + rename.

  • Short-circuits when the new content is byte-identical to the existing file — no prompt, no churn.
  • Preserves the existing file mode on overwrite.
  • Refuses payloads above 50 MB to keep the approval prompt meaningful.
EditAsks first

Exact-string replacement. old_string must be unique unless replace_all is set.

  • If old_string matches more than once, Edit refuses with a count and asks for more context — silent first-match-wins is a common source of broken refactors.
  • no-op edit (old_string == new_string) is rejected before any prompt.
  • Atomic write into a sibling tmp file in the target directory, then rename — file mode is preserved.
NotebookEditAsks first

Replace, insert, or delete a cell inside a Jupyter notebook (.ipynb).

  • Targets a cell by id or by 0-based index; insert defaults to end-of-notebook when neither is given.
  • Mutating a code cell wipes its stale outputs and execution_count automatically.
  • Notebook is parsed as JSON, mutated in place, and written atomically — a crash mid-write cannot leave a half-written .ipynb on disk.

Shell

Bash is the agent's hands. Approval-gated, output-streamed, group-killed on timeout.

BashAsks first

Execute a POSIX shell command. Captures stdout+stderr with a configurable timeout.

  • Streams output incrementally — long-running commands show progress in the transcript instead of going dark.
  • Default timeout 120 s, max 600 s. Output capped at 30 000 characters with a marker; the pipe is drained past the cap so the child doesn't block.
  • Spawns the child in its own process group; on timeout the entire group is SIGKILLed — no orphaned tail processes.
  • An informational denylist (rm -rf /, sudo rm, mkfs, dd if=, fork bombs) prepends a [danger confirmed] note to the result if you approve one of those.

Web

Outbound HTTP. WebFetch when you have a URL; WebSearch when you need to find one.

WebFetchAuto

Fetch a URL and return its text content (HTML stripped to markdown-like text).

  • Upgrades http:// to https:// before issuing the request.
  • Follows redirects, surfaces 401 / 403 explicitly, and returns the cleaned text body — not the raw HTML.
  • Pairs well with the prompt argument so the agent can call WebFetch with a why, not just a URL.
WebSearchAuto

Issue a keyword query and return ranked title / snippet / URL rows.

  • DuckDuckGo HTML endpoint by default; swap providers via FULCRUM_SEARCH_PROVIDER (planned).
  • Supports allowed_domains and blocked_domains so you can scope a search to docs.python.org without scraping the whole web.
  • Unwraps DDG's /l/?uddg= redirector so the URLs returned to the model are the real destinations.

Memory & knowledge

Persistent markdown at ~/.fulcrum/memory/. The index is auto-injected at session start; full bodies are loaded on demand.

SaveMemoryAsks first

Persist a memory entry that future sessions will see in their system prompt.

  • Four types — user (identity / role), feedback (rules they've given you), project (current effort), reference (external pointers).
  • Stored as one markdown file per entry plus a top-level MEMORY.md index.
  • The index is auto-injected at session start; only the one-line description is in the prompt — the full body is loaded by ReadMemory.
ReadMemoryAuto

Load the full body of a saved memory by filename.

  • Pass the filename with or without .md.
  • Use this when an index entry's description sounds relevant to the current task — the body isn't in the prompt by default.
ListMemoriesAuto

List currently saved memories with their type and one-line description.

  • Optional type filter restricts the list to one of user / feedback / project / reference.
  • Useful as a discovery step before ReadMemory pulls the full body.
DeleteMemoryAsks first

Delete a memory entry by file name.

  • Approval-gated even though the file is in your home dir — accidental memory loss is hard to recover from.

Sub-agents

Spawn an agent with its own context window and tool loop. Profiles let you save a role and reuse it.

AgentAsks first

Spawn a sub-agent with a fresh context window and run a focused task to completion.

  • Sub-agent inherits the parent's REGISTRY minus Agent / EnterPlanMode / ExitPlanMode (no infinite recursion).
  • subagent_type='<name>' loads a profile from ~/.fulcrum/agents/ or ~/.claude/agents/. Profile sets the system prompt, tool whitelist, and model — and overrides any tools or model arg passed inline.
  • Streaming events from the sub-agent are collected; the tool returns the assembled final text to the parent agent.
SaveAgentAsks first

Save a named sub-agent profile to ~/.fulcrum/agents/<slug>.md.

  • Profile = YAML frontmatter (name, description, tools, model, whenToUse) + a markdown body that becomes the agent's system prompt.
  • Pass overwrite=true to replace an existing profile of the same name.
ListAgentsAuto

List every available sub-agent profile with role, tools, model, and source path.

  • Reads ~/.fulcrum/agents/, ~/.claude/agents/, and any plugin-supplied agents.
  • Use this before Agent + subagent_type so you call a real profile instead of guessing.
DeleteAgentAsks first

Delete a user-dir agent profile by name.

  • Claude Code agents and plugin agents are read-only here — you can only delete things you saved with SaveAgent.

Skills

Skills are reusable prompt templates the agent can invoke by slug. Bundled skills ship in the binary; user skills live at ~/.fulcrum/skills/.

SkillAuto

Execute a named skill from ~/.fulcrum/skills/.

  • The tool's own description is rebuilt at runtime to list every loaded skill — so the model sees which slugs it can call without a separate discovery step.
  • Optional args string is appended to the skill body so a single skill can take parameters.
SaveSkillAsks first

Create a new skill at ~/.fulcrum/skills/<slug>.md.

  • Frontmatter supports whenToUse (when the agent should reach for it), allowedTools (restrict the skill's tool surface), and model (override the active model just for this skill).
ListSkillsAuto

List every available skill with description and source path.

  • Bundled and user-dir skills are merged — the path tells you which is which.
DeleteSkillAsks first

Delete a user-dir skill by name.

  • Bundled skills cannot be deleted — they reappear on next start.

Approval & interaction

Tools that bend execution flow — pausing for the human, deferring, or signalling planning intent.

AskUserQuestionAsks first

Ask the user a question mid-task and read the response.

  • V1 stub: routes through ctx.approve and returns yes / no.
  • Phase 3 will upgrade this to a TUI question widget with free-form and multiple-choice replies.
BriefAuto

Summarize a block of text into a compact brief via the LLM.

  • Useful when a long shell output or web page is about to bloat the context window — Brief boils it down before the next turn.
  • Preserves file paths, decisions, and numeric values; everything else is fair game to compress.
  • max_tokens is a soft cap with a 4-chars-per-token heuristic.
EnterPlanModeAuto

Submit a proposed plan for user approval before executing further tool calls.

  • Sets a module-level _current_plan flag; Phase 3 of the agent loop will gate execution on it.
  • Pair with ExitPlanMode to resume normal tool execution once the user signs off.
ExitPlanModeAuto

Exit plan mode and resume normal tool execution.

  • Clears the _current_plan flag — no payload required.
TodoWriteAuto

Append items to the session todo list shown in the TUI sidebar.

  • Each item carries a status — pending, in_progress, or completed.
  • Persists at ~/.fulcrum/sessions/<session>/todos.json (or ~/.fulcrum/todos.json when no session id is set).

Task registry

Heavier than TodoWrite. Tracks structured tasks across the session — useful when one prompt fans out into a dependency graph of sub-jobs.

TaskCreateAuto

Create a new task in the session task registry.

  • Fields: title, active_form (a present-tense progress label), optional description, optional dependencies on other task ids.
TaskListAuto

List tasks in the session registry, optionally filtered by status.

  • Read-only snapshot — useful before TaskUpdate or TaskStop.
TaskGetAuto

Fetch a single task by id with full details.

  • Returns the full record — title, description, output, owner, status — not just the summary line.
TaskUpdateAuto

Update a tracked task's status, description, or output.

  • The output field captures the artifact a task produced (a path, a diff, a finding) so a later task can consume it.
TaskStopAuto

Cancel a task — sets its status to CANCELLED.

  • Doesn't touch dependencies — downstream tasks see the cancellation and decide for themselves.

Background work

Tools that run while the agent moves on. Cron schedules; Monitor watches; Sleep yields the loop.

CronCreateAsks first

Create a scheduled job (5-field cron syntax or @once <ISO> for one-shot).

  • V1 records the schedule on disk at ~/.fulcrum/cron.json — an external runner is required to actually execute jobs.
  • Each job carries a prompt that will be fed to fulcrum exec when it fires.
CronDeleteAsks first

Delete a scheduled cron job by id.

  • ID comes from CronList — names are not unique.
CronListAuto

List every scheduled cron job.

  • Shows id, name, schedule, enabled flag, and last run timestamp.
MonitorAsks first

Watch a long-running shell command's output until a regex matches or the timeout fires.

  • Use cases: tailing logs, polling for build completion, waiting for a dev server's ready line.
  • Spawns the child in its own process group; on match or timeout the entire group is killed cleanly.
  • Returns a [matched] / [exit N] / [timeout] prefix plus the captured output, capped at 30 000 chars by default.
SleepAuto

Pause execution for a bounded duration.

  • Clamped to [0, 600 000] ms — an over-eager model cannot wedge the loop with a multi-hour wait.
  • Useful for letting a deploy propagate or a file watcher debounce before the next tool call.

Git worktrees

Operate on multiple branches at once without disturbing the primary checkout.

EnterWorktreeAsks first

Create a git worktree on a new or existing branch.

  • Defaults the path to ../<repo>-<branch> and the base ref to HEAD.
  • Returns the worktree path; subsequent file ops should target it explicitly.
ExitWorktreeAsks first

Remove a git worktree, optionally deleting the associated branch.

  • Recovers the branch name from git worktree list --porcelain before removal so delete_branch can target the right ref.
  • Pass force=true when the worktree has uncommitted changes.

Language servers

Real code intelligence — not regex pretending. Spawns a fresh language server per call.

LSPAuto

Code intelligence via Language Server Protocol — go-to-definition, find references, hover, document symbols.

  • Four operations: definition, references, hover (markdown), symbols (the document outline).
  • Server is selected by file extension; if none is registered or installed, the call fails with a clear diagnostic.
  • Read-only — never prompts.

MCP — external tools

Bridge to the Model Context Protocol. Servers listed in ~/.fulcrum/mcp.json expose their resources to the agent alongside the built-ins.

ListMcpResourcesAuto

Enumerate resources across configured MCP servers.

  • Pass server to restrict to one server; omit to fan out across all configured servers.
  • Servers that fail to connect are logged inline in the output instead of aborting the whole call.
ReadMcpResourceAuto

Read a resource by URI from a configured MCP server.

  • Concatenates any text content items the server returns; binary blobs are summarised as [binary blob, N chars base64].
McpAuthAuto

Authenticate against an MCP server.

  • V1 stub: returns instructions for hand-editing ~/.fulcrum/mcp.json (bearer tokens for stdio servers, custom headers for sse / http).
  • OAuth device flow is deferred to a later phase.

Other tools

Less-frequently-reached tools that still ship in the registry — discovery, REPL, vision, structured output.

ToolSearchAuto

Keyword search across the tool registry. Returns matching tools and their schemas.

  • Name matches outweigh description matches by 100x — short, well-named tools rank above tools whose body happens to mention the query.
  • Truncates each schema to 300 chars so the result fits in a single context turn.
REPLAsks first

Evaluate Python code in a session-scoped persistent namespace.

  • State persists across calls within one session — one fulcrum session == one Python process == one shared namespace.
  • reset=true wipes the namespace and starts clean.
  • stdout / stderr are captured; output is capped at 30 000 chars.
VisionServiceAuto

Describe an image at a local path using the configured vision model.

  • Reads PNG, JPEG, GIF, WEBP, BMP and base64-encodes them as a data URL for the vision model (Llama-4-Maverick on scx.ai by default).
  • image_path='clipboard' reads the macOS clipboard image — handy for screenshots whose temp file was reaped before the agent saw it.
  • Handles macOS quirks: drag-drop backslash escapes, U+202F narrow-no-break-space in screencapture filenames, and TCC permission denials with a useful diagnostic.
SyntheticOutputAuto

Emit arbitrary structured data to the caller without invoking other side-effects.

  • Supports JSON, YAML (when pyyaml is installed; falls back to JSON otherwise), and plain text.
  • Useful for orchestration patterns where the agent's caller wants a machine-readable answer rather than prose.

Approval & permissions

The default posture: write tools (Edit, Write, Bash, NotebookEdit, REPL, EnterWorktree, ExitWorktree, the cron mutators, SaveSkill, SaveAgent, SaveMemory, DeleteMemory, DeleteSkill, DeleteAgent, Agent, Monitor) call ctx.approve with a one-line description before running. The TUI shows you the action, you accept or deny, the tool runs or returns a denial.

Press Ctrl+Y to toggle session-wide auto-approve. The transcript shows the indicator persistently until you toggle it back off — there is no accidental forever-on. Per-call overrides live in the approval modal itself: allow once, always for this pattern, or never.

Read-only tools never prompt. The full list of unattended tools is every card tagged Auto above — Read, Grep, Glob, Ls, WebFetch, WebSearch, ListMemories, ReadMemory, ListAgents, ListSkills, Skill, Brief, EnterPlanMode, ExitPlanMode, TodoWrite, every Task* tool, CronList, Sleep, LSP, ToolSearch, SyntheticOutput, VisionService, and the three MCP discovery tools.

Adding your own tools

Two extension points, with different surfaces — don't confuse them.

MCP servers — the supported way to add new tools

Drop a server entry in ~/.fulcrum/mcp.json(the format is compatible with Claude Code's mcpServersconfig), restart, and the new tools appear alongside the built-ins in the agent's toolbelt. Stdio and SSE transports are both supported. See the MCP section of the docs overview for the JSON shape.

Plugins — slash commands, not tools

A Python file in ~/.fulcrum/plugins/ with @register_command adds a slash command — a user-facing trigger you type in the prompt. It does not add a tool the model can invoke. If you want the model to be able to reach a new capability on its own, expose it via MCP. See the plugins section of the docs overview for an example.

Next steps