Changelog
v1.7.1 — 2026-08-12
Added
- Media on
stream().agent.stream(prompt, images=[...], files=[...])now takes the same attachments asrun()— images by URL, path or base64 (vision models); text, markdown and code inlined; PDFs as native document blocks where the provider reads them.
v1.7.0 — 2026-08-12 — the working set
The largest capability release yet. One theme: do the most with the fewest tokens — reach for a tool only when the turn needs it, and keep the rest out of the request until it does.
Added
- Deferred tool loading (
Agent(deferred_tools=True)). A small core set keeps its schema in every request; everything else — including MCP tools — is listed by name only untiltool_search(or a direct call) loads it. On a many-tool turn the fixed per-step schema cost drops to the working set. - Files and images, straight to the model.
run(images=[...], files=[...])— no read-it-yourself round-trip. Text/markdown/code inline on every provider; PDFs as document blocks where supported; images on vision models. - Native structured output. Hand
Agenta schema and the run returns that type, validated, on providers that support response formats — with a prompt-and-validate fallback everywhere else. - Parallel, read-safe tools. Read-only tool groups fan out concurrently; writes stay serial, so a fast run never races itself into a corrupt state.
- Powerful sub-agents with their own toolset containment and timeouts, and
an
orchestratorrole. - MCP hardening. Unconditional tool-name sanitization for every server,
per-request timeouts, respawn re-handshake, and server
instructionssurfaced once in the system prompt. - Prompt caching across the system prompt, tools, and the conversation prefix on providers that support it, plus in-run compaction and context eviction to keep long runs bounded.
- A full streaming event feed — every step, tool input/output delta, and a per-run decision narration you can render live.
v1.5.1 — 2026-08-08
Added
- Guides for three features that shipped without them. Triggers, delegation, and agents as tools each had public API and no page explaining when to reach for it.
SqliteTriggerQueue,InMemoryTriggerQueue,fire_all,DelegationPolicyandDelegationAdviceare exported from the package root. Found by checking that every import in the new guides resolves:TriggerRegistrywas exported without the queue you configure it with, so the durable setup — the default anybody running this in production wants — could not be written from the top-level import at all. A test now pins the surface the documentation uses.
v1.5.0 — 2026-08-08
Added
AgentTool— an agent as a tool. Wrap any agent and hand it to another as one focused callable, so a researcher, a reviewer and a writer become tools a coordinating agent picks between by description. Unlikesub_agent, which builds a child from the parent, this delegates to an agent you configured yourself — its own model, its own tools, its own session if you give it one. Nested events surface through the parent's stream, so a delegated run is visible rather than a silence.
Fixed
- A failing child no longer ends the parent's turn.
AgentToollet a child's exception propagate, so one provider being down took the whole run with it. Every other tool reports failure as a result the model can act on; this one does now too, and the parent can say so, try something else, or answer without it. - Delegation cannot recurse forever. An agent holding a tool that
wraps an agent holding the same tool would recurse until something ran
out.
sub_agentalready capped this;AgentToolis the same hazard by another name, so it shares the counter rather than keeping its own — and the refusal says to do the task directly, because a cap that does not name the alternative just gets retried. - A child that returns nothing is no longer reported as success.
v1.4.0 — 2026-08-08
Scheduled jobs stop sharing one agent, skills come from the project, and tool output streams while it is produced.
Added
- Per-job agent configuration. Every scheduled job carried the same
process-wide agent, so "summarise the inbox hourly on a cheap model" and
"audit the repo nightly on a good one" could not coexist. A job now
persists its own provider, model, role, project root, runtime mode,
permission mode, guardrails, MCPs, connections, skills and iteration cap
—
ScheduledAgentConfig, resolved per job byScheduledAgentFactory. The SQLite store migrates itself: existing databases gain the new columns on open, and a job written by an older version still runs. - Project skills.
discover_project_skillsandload_markdown_skillread skills from the repository the agent is working in, so a team's conventions live beside the code they describe rather than in a configuration screen. - Streaming tool output.
ToolOutputChunkandToolRunOutputlet a long-running tool report as it goes instead of arriving whole at the end. - Concurrent web search.
web_searchacceptsqueriesas well asqueryand runs them in parallel. Either, never both — an empty call answers with which of the two to pass.
Fixed
- A permanently broken scheduled job now pauses. Failures were counted
and nothing acted on the count, so a job whose provider was gone ran
every interval for as long as the daemon lived, burning quota and
filling the log with one repeated line. Paused after five consecutive
failures — paused rather than deleted, because the configuration is
intact and
jobs resumeis one command. Resuming clears the count, so a job somebody fixed is not paused again by the history that paused it.max_consecutive_failures=0switches the behaviour off.
v1.3.3 — 2026-08-07
Added
- Breadth as a structural signal. "Go through every document attached"
names no number and no filename, so counting lists, targets and quantities
missed it — and 1.3.2's corroboration floor would then have declined it.
A distributive determiner over a noun ("every document", "each of our
repos", "all the open PRs") now counts. It is grammar rather than
vocabulary, so it holds for wording nobody anticipated, and it reports no
count: breadth says "more than one", not how many, and inventing a number
would feed a fake quantity to the
min_itemsfilter. An adverbial "all" — "is it all good", "tell me all about it" — is not breadth.
v1.3.2 — 2026-08-07
Fixed
- A model may no longer invent a decomposition. Asked "Can you look for
the latest AI news?", Gemma 4 answered
decompose: true, items: 3, "news can be split by topic or source"— three sub-agents for one web search, and not one of those topics appears in the request. The assessor was asking "could this be split?", and almost anything could. It now counts only the pieces the task itself names, is told plainly that a single search or a single read is one call, and a model's yes must be corroborated by something actually in the text. The structural floor already raised a model that undercounted; it now also declines one that overcounted. The count it saw is still reported — overruled, not erased.
v1.3.1 — 2026-08-07
Fixed
delegation=no longer attachessub_agenton every turn. Asked "look for the latest AI news", an agent with automatic delegation on spawned three research sub-agents instead of running one web search. The tool was attached unconditionally on the reasoning that a model deciding mid-run to delegate must find it there; measured against a smaller model, that reasoning fails — a tool on the table gets used, and given a choice between a search and a research crew it takes the crew. The policy already judges each task for the directive, and the toolbox now follows the same judgement. An explicitly passedSubAgentToolis untouched.sub_agentrefuses a task with no substance in it. Observed:sub_agent(task=","), which the tool accepted, spending a model call to return an error. A child sees nothing of the parent's conversation, so the task is its entire brief. The refusal names the alternative, because one that does not just gets retried.- Background delegation says there is no "later". The tool and the
directive now state that anything started with
background=truemust be collected in the same turn — a run ends with its answer, and an uncollected task is discarded. Without this, models announced background work and promised to report back on results that were never coming. - A dashboard blueprint f-string that only parsed on Python 3.12+.
v1.3.0 — 2026-08-06
An agent you have to ask is a tool. An agent that reacts is a colleague. This release is the second half: triggers — something happens, and the agent runs.
Added
shipit_agent.triggers— a trigger registry, a durable queue, and a worker loop.registry.on("gmail")decorates a function that turns an event into a prompt. A trigger builds a prompt, not an agent: the run stays on the agent you already configured, with your credentials, permissions and budget, rather than a second agent nobody is watching.registry.fire(source, data)records and returns. It runs nothing. A webhook must answer in milliseconds and an agent takes seconds; a sender that times out delivers the same email again.registry.drain(agent)runs what is queued and reports each run.registry.run_forever(agent, stop=…)is the worker, stoppable.
SqliteTriggerQueue— the default, and durable on purpose. An event that arrives while nothing is running must still be there afterwards, or "runs on every email" is a claim that fails quietly at 3am. Claiming takes the row, so two workers can drain one queue; an abandoned claim expires rather than stranding the event.- Poison-event handling — an event that fails
max_attemptstimes stops, instead of hiding everything queued behind it. fire_all()for batches, andregistry.summary()for "what is wired, what is waiting" — the data behind a Live badge.
Notes
A handler returning None is how a trigger filters: only RSVPs, only
failures. That is a skip, not an error, and it still consumes the event.
InMemoryTriggerQueue is named the way it is to be hard to reach for by
accident — it is for tests.
v1.2.0 — 2026-08-06
One question, asked of every surface: can you see what the agent did? A run now reports itself well enough to draw a product from — and, where the agent used to answer and forget, it can leave something behind.
Added
Watching a run
- The tree view — the shape of a run instead of its prose: every call
named with its status, the opening intent labelled "Understanding request",
each later paragraph a "Decision", the last one the "Final answer". On a
terminal it redraws in place while the run proceeds, keeping the trunk open
(
├─ working…) until it ends, then erases the draft and writes one clean tree.agent.run_live(style="tree"),render_tree(events, detail=True). - The live panel — an HTML chat card that redraws in a Jupyter cell as the
agent works: tokens land with a caret, tool rows appear in flight and
settle, real output folds away behind each call, cards interrupt the flow,
and the footer counts tokens.
watch(agent, prompt),shape="tree"for the tree,render_chat_html(events)for a finished run. Every selector is scoped so the styles cannot leak into the page around it, and redraws are throttled — a full re-render per token is O(n²) DOM churn that stutters exactly when the answer gets long. - The UI timeline — the runtime's events translated into what a frontend
draws:
reasoning_summary,tool_group_started,tool_call_started,tool_call_completed,agent_decision,artifact_created,final_response. Plain JSON, and causal — a group's settled title arrives in itscompletedstep, so a client never has to undraw a row.stream_timeline(agent, prompt);render_markdown(events)prints the same run as a report. - Progress narration —
Agent(progress_summaries=True, decision_llm=…). A second, cheap model says what the agent is doing while it does it. It never reads the system prompt orreasoning_contentand is called withtools=[], so what it reports is what an observer could have watched happen; a failure emitsprogress_summary_failedand the run continues. Off by default: it adds a real LLM call per step. - Tool groups — one per iteration, carried on
tool_called/tool_completedasgroup_id, so a UI can draw one expandable box per turn (2 tools · 13.0ms) however much narration lands between the calls. final_answer— the answer as its own event, just beforerun_completed, so a client does not have to infer which event carries it.
Leaving something behind
- Apps —
list_blueprints,create_app,set_app_binding,use_app, shipped as builtins under<project>/.shipit/apps. The agent writes a program into the workspace, wires resources into it, and runs it — today, and next week, with no model in the loop. An app is a directory withapp.pyexportingrun(input, env); it runs in a subprocess with no credentials, and itsenvcrosses the same capability bridge code mode uses, so every resource call is gated exactly as the equivalent tool call would be. An app sees only the bindings its manifest names. - Six blueprints —
report,csv_summary,page, and three that produce something worth looking at:dashboard(headline cards and a bar chart),sheet(column letters, row numbers, flagged cells) andworkflow(a pipeline as boxes and connectors). All self-contained — no CDN, no fonts, no script tags — because an artifact that needs the network is not one you can send anyone. - Artifact cards — a file a run produced is a card, not a path in a log:
Q2 Kickoff Brief · Doc · Click to open, in the panel, the tree and the timeline. Any tool that declares a path in its result metadata gets one.
Reaching further
- Automatic delegation —
Agent(delegation=True). Thesub_agenttool is guaranteed to exist, built from the agent's own LLM and its read-only tools; the task is sized by a model (ModelAssessor, one cheap cached call) with a structural count as the fallback and the floor; and the directive is appended to the task, not the system prompt — measured against Gemma 4, that difference is 0 delegations versus 6. It never delegates behind the model's back. - Connection requests — the registry knew what was connected; nothing
turned "I need Slack" into something a user could answer. The agent's
request now emits
connection_requestedfrom both loops, the panel draws a card with the reason, andregistry.resolve(id, accepted=…, credential=…)closes the loop — on accept the credential is stored, so the next state check reads CONNECTED rather than asking again.
Fixed
- The async runtime's
tool_completedwas missingtoolandcall_id, so its transcript could only guess which outcome belonged to which call. read_fileproduced artifact cards for files it merely read.- An artifact card split the tool group that made it.
run_live()raises on an unknownstyleinstead of silently rendering the default view.write_transcript()acceptedtitleandmodelbut droppedprompt.use_appwrote a file and never declared it, so the run produced a page and the transcript showed a JSON blob.- Apps ran in their own install directory, so an app given
path="guests.csv"found nothing.AppStore.run()runs them where the agent works. deny=["*"]denying allow-listed tools is now documented where you meet it, with the correct pattern (allow=[…], default_decision=DENY) beside it.
Notes
progress_summariesanddelegationare both off by default. Each adds real LLM calls, and a runtime that doubles your bill on upgrade is not one you can trust.- Two live notebooks ship with their outputs committed, run against
bedrock-mantle/google.gemma-4-26b-a4b:74_live_streaming_gemma.ipynb,75_live_ui_and_subagents.ipynband76_apps_and_analysis.ipynb. - Still open, and named rather than hidden: the async runtime has no progress
narration and no tool groups, and
Agent.decision_llmsits second in the field order, soAgent(llm, "prompt")positionally assigns the prompt to it. Both are tracked indocs/design/cloudflare-os-gap.md.
v1.1.0 — 2026-08-06
A single release focused on one question: what does an agent look like while
it works, and what should it be allowed to do while you are not watching?
Studied against Cloudflare OS (open source) and adapted rather than copied —
the design notes, including what was deliberately not ported and why, are in
docs/design/modern-agent-upgrade.md.
Added
- The Narrator — a transcript instead of a log. Every tool call renders as
a human verb and target (
Read app.py,Ran code const risk = scoreAcc…), consecutive calls with no prose between them collapse into one row, and the run closes with tokens and cost. Present tense in flight, past tense once it lands; in-place on a TTY, byte-stable when piped.agent.run_live(style= "modern"),shipit code --style,/stylein the REPL. The 50-tool verb table is a set of defaults —register_verb()overrides any of it, and unknown MCP tools narrate through real English morphology rather than crashing on an exhaustive match. - Tool contracts — every one of the 51 built-ins now declares what it is
(
read_only,action_kind,implements_revert,await_decision,auto_approvable,destructive) instead of being guessed from its name. Before this, exactly one tool declaredread_only. - Deferred approvals — a side-effecting call the policy marks
askis queued rather than blocked on, so the agent finishes and you review the batch. Auto-approval rules key on a stableaction_kindtag, applied in order, never past a manual gate, and requiring both the contract's verdict and your enabled rule.shipit code --defer-approvals. - Lockdown — once a tool reports it returned sensitive data, the run may only make observations; every action is denied for the rest of it. Closes a real hole: nothing previously stopped an agent reading your customer list and posting it to Slack in the same turn.
- Code mode —
Agent(code_mode=True)collapses connectors into anenvof bindings reachable from oneexecute_codecall, withdescribe_bindingfor on-demand discovery. Measured on the real catalogue: 25,932 → 11,174 tokens per model call, 57% smaller.envreaches the parent over a capability bridge — the code runs in a subprocess holding a socket, not credentials, and every binding call is gated exactly as the direct tool call would be. - Connections —
connectionslists what is connected, what needs authenticating and what is missing, with per-auth-kind guidance, and lets the agent request one with a reason instead of failing mid-task. - Streaming, three ways —
agent.stream()(raw events),agent.narrate()(settled transcript rows, so a custom UI need not reimplement the collapsing), andagent.stream_sse()(wire-ready). Frames are labelled canonical or provisional and carry a per-processstream_generation, so a browser that reconnects knows what to keep and what to discard. NewPOST /v1/streamon the server;/healthreports the generation. - Checkpoint compaction — per-model token budgets, cuts at a turn (or step) boundary rather than a fixed message count, a six-heading handoff summary, and an explicit instruction not to follow instructions inside the transcript being summarized. Canonical history is preserved; only the replay window moves.
give_up— a real tool with a required reason, surfaced asresult.metadata["gave_up"], replacing inference from prose.- Streaming tool arguments — a file or command appears as the model writes it. Supported on all 13 shipped adapters (Anthropic, OpenAI, Bedrock, Gemini, Vertex, Groq, Together, Ollama, LiteLLM and its proxy); adapters without it degrade to arguments arriving whole.
- Revert —
queue.revert(id)for filesystem writes, snapshot-based. - Shareable transcripts —
--share run.htmlwrites one self-contained file: no network requests, no build step, light and dark.
Changed
sub_agentis now an actual sub-agent. It previously calledllm.complete()once withmessages=[]andtools=[]— no loop, no tools. It now runs a realAgentwith an inherited toolset, supportsagent_typefrom the built-in role registry, runs in parallel viabackground/collect, and streams its work into the parent's transcript. A sub-agent can never do more than its parent: permissions, approvals and guardrails are inherited verbatim, and delegation is depth-capped.- One runtime core.
runtime.pyandasync_runtime.pyhad drifted to the point that ten capabilities existed only in the sync loop. The shared decisions now live inruntime_core.pyand both inherit them; a parity suite asserts neither may override or reimplement one. - A missing tool argument is now a result the model can act on rather than a
KeyError— it names the argument and lists what the tool requires.
Fixed
tool_deniedcarried neithertoolnorcall_id, in both runtimes, so a blocked call was invisible to any renderer.sub_agent'scontextparameter was silently dropped:ToolRunnerstripscontextandselfas reserved names, so supporting context never arrived. Renamed todetails.EventTypehad drifted —tool_deniedandtext_deltawere emitted but undeclared.get_model_limitssplit on.to strip vendor prefixes, turninggemini-2.5-prointo5-pro.- An explicit
context_window_tokenshad an output reservation subtracted from it, so a value of 100 produced a budget of 1. - 18 contracts promised
implements_revertwith zero implementations behind it. Now 7 promise it, all backed by a reverter, enforced by a test.
v1.0.18 — 2026-07-31
Added
- The
shipitCLI, rebuilt as a modern package —shipit code(coding agent rooted in your repo: playbook prompt, --plan/--yes modes, y/n/always prompts),shipit serve(AgentServer: the agent as an OpenAI-compatible API with SSE streaming + Bearer auth),shipit run --role/--guardrails, and catalogs (roles | models | mcp | tools) with a curated latest-model list (claude-opus-5/sonnet-5, gpt-5.6/5.5, Gemma 4, gpt-oss). Stdlib UI kit: named palette, NO_COLOR/FORCE_COLOR, encoding-safe banners. - Guardrails engine — four gates (prompt-injection input blocking, secret/PII output redaction, tool-argument deny rules, indirect-injection sanitization of tool outputs) + max_tool_calls ceiling, strict()/ standard() presets, optional fail-open LLM judge; guardrail_triggered events; Agent(guardrails=...).
- Self-healing tool calls — text-emitted calls (<tool_call> tags, fenced JSON, bare call-shaped JSON) promoted to structured executions: declared-tools-only, span-exact removal, response-side only; plus nudge-on-stall (one capped re-prompt on intent-without-action).
- New builtin tools —
git_ops(structured git, fixed argv, push/reset gated off),notebook_edit(structural .ipynb editing),deep_research(multi-angle sweep → deduped sources → citation-ready digest). - RAG chunk-overlap budgeting — carried overlap is capped by the room remaining under the chunk target so near-full chunks never overflow the embedder window.
- Notebooks 72 (guardrails + deep research, live Bedrock) and 73 (CLI +
power tools), docs guide
guides/shipit-cli.md, README CLI section. - Human-in-the-loop everywhere —
console_permission_prompt(): one reusable [y]/[n]/[a]lways approval callback for any agent; powersshipit chatandshipit code; shareable always-allowed set, injectable I/O, EOF→deny. - Bottom-pinned chat TUI —
BottomInputTerminal(VT100 scroll regions, stdlib): chat scrolls, input never moves; auto-on for real TTYs inshipit chat, transparent plain fallback elsewhere. shipit browse— computer use from the CLI: vision loop streamed as live cards,--showvisible window, consent persistence.--mcpflag + official Playwright MCP — attach catalog servers torun/code/serve/doctorfrom the command line; the newplaywrightentry gives any tool-calling model accessibility-tree browser control.- RAG + Agent example (24) — RRF-fused hybrid retrieval with [document-id] citations, fully offline.
v1.0.17 — 2026-07-17
Observability + live browsing. Langfuse support for BOTH server generations, a downloadable-files tool, a fully observable and watchable computer-use loop, and a security hardening pass. 2006 tests passing (+37 new). 0 regressions.
Added
LangfuseExporter(shipit_agent.tracing_exporters) — ship whole agent runs to Langfuse as a root trace + one child span per tool call (real durations, inputs/outputs, error status). Speaks both server generations with zero SDK dependency: v3 via native OTLP (/api/public/otel/v1/traces), v2 via the classic batch API (/api/public/ingestion);api_version="auto"probes/api/public/healthand picks the wire format. Works with every adapter — including Gemma-4-on-mantle calls that bypass litellm callbacks. Transport failures never break the run. (For LLM-call analytics via litellm: uselitellm.callbacks=["langfuse_otel"]against v3 servers — the classic"langfuse"callback is v2-SDK-shaped and 500s on v3.)download_filebuiltin — binary-safe URL downloads (zip/csv/image/pdf): 64KB streaming with a hard size cap (partials removed on abort), reuses open_url's SSRF/scheme guard, Content-Disposition filenames, no silent overwrites, absolute path returned in metadata.ComputerUseAgent.stream()— the screenshot→reason→act loop is now observable: standard events (tool_called/tool_completed/tool_failedasbrowser.<action>withcall_id+duration_ms) render as live tool cards viaStreamRenderer;run()unchanged.- Watchable, reliable live browsing —
slow_mo=(see the mouse move),settle_ms=500(screenshots taken AFTER the page reacts, not mid-animation),device_scale_factor=1(exact coordinate mapping on Retina), typed keystrokes withdelay=40;storage_state=/save_storage_state()persist accepted consent across runs. - Obstacle-autonomous computer use — system prompt now instructs the model to dismiss cookie/consent walls ("Accept all"), close popups, skip sign-ins, route around CAPTCHAs, and verify field focus before typing.
Fixed
- Quoted action args — models emitting
ACTION: navigate "https://…"produced literal quote characters that Playwright rejects ("Cannot navigate to invalid URL"); quotes (and aurl=prefix) are now stripped in both the text and Anthropic tool_use parsers. - Security —
research_briefnow enforces http/https before fetching (URLs come from model-influenced search results;file:///blocked);AdaptiveAgent.create_toolnow honorscan_create_tools=False(previously ignored) and documents its trusted-developer-code-only contract. GitHub CodeQL/Dependabot: 0 open; pip-audit clean on all shipit-relevant packages.
v1.0.16 — 2026-07-10
The live experience — streaming, cancellation, and professional-grade ergonomics. Real token streaming everywhere, one-call live runs with rich tool cards, safe stops, stale-proof edits, model-written compaction, and a sharper CLI. Works with any LLM provider. 1969 tests passing (+13 new). 0 regressions.
Token streaming, everywhere
OpenAIChatLLMstreams for real (was a silent TODO): tokens hit the callback as generated, tool-call fragments stitched by index, usage captured from the final chunk; gateways that ignorestream=Truedegrade gracefully. Lights up Gemma 4 on Bedrock mantle, Groq, and every OpenAI-compatible endpoint.AnthropicChatLLMstreams via the SDK'smessages.streamhelper — all existing parsing (thinking blocks, tool use, server tools, citations) unchanged.
The live experience
Agent.run_live(prompt)— tokens print as generated, tool calls render as cards with args/status/duration, a✔ donefooter closes the run; returns the final answer text.StreamRenderer— the underlying renderer for custom loops;style="rich"(automatic on TTYs) draws rich ⏺/⎿ cards with ANSI colors; prints the answer at the end for non-streaming adapters.agent.cancel()— thread-safe ESC: stops at the next checkpoint, emitsrun_cancelled, returns normally withmetadata["cancelled"]; skipped batch tools get synthetic results so message pairing stays valid.
Reliability
- Edit hardening —
edit_fileblocks when the file changed on disk after the lastread_file(external modification → re-read hint) and returns a compact unified diff with every patch (metadata["diff"]). - LLM-powered compaction — near the context window, old turns are
summarized by the model (decisions, facts, paths, open threads; ~300
words) with a mechanical fallback; the
context_compactedevent now fires reliably.
CLI
- Live
StreamRendererturns (real tokens + cards; spinner retired), inline [y]es / [n]o / [a]lways prompts forask-gated tools (session-persistent always-allows), and--continueto resume the most recent session (~/.shipit/sessions). Fixed a--session-dircrash.
Examples & notebooks
examples/23_bedrock_model_switching.py— Gemma 4 26B ↔ gpt-oss-120B, one function, live-verified.notebooks/71_full_test_drive.ipynb— 13 in-depth sections exercising every capability, executed end-to-end (live Bedrock cells + offline).
v1.0.15 — 2026-07-10
The Super Agent — every sector, clean logs, real deliverables. One release that makes a shipit agent useful to a finance analyst, a marketer, an engineer, a designer, a researcher, and a sales rep alike — and makes every run readable. All of it works with any LLM provider.
Sector specialists — Agent.for_role
- One line to a specialist —
Agent.for_role("finance-analyst", llm=llm)turns any of the 40+ prebuilt role definitions (finance, marketing, engineering, design, research, sales, support, HR, …) into a runnable agent: the role's prompt, its matching builtin tools, and its iteration budget. - Did-you-mean errors — unknown ids raise a
ValueErrorlisting the closest matching roles. - Deliverable-ready roles — 14 specialists (finance-analyst,
marketing-writer, researcher, data-analyst, sales roles, …) now carry the new
build_documenttool.
Prebuilt MCP catalog — connect_mcp
- 12 well-known servers by name —
connect_mcp("github"),connect_mcp("filesystem", args=["/repo"]),connect_mcp("postgres", args=[url]), plus slack, sqlite, puppeteer, brave-search, fetch, memory, sentry, gitlab, and google-maps — each on a persistent stdio transport. - Fail-fast validation — required env vars and the launcher binary
(
npx/uvx) are checked before anything starts; misconfiguration is one clear message. - Resilient MCP calls — a failing MCP tool call (server down, timeout) now
returns a readable tool result the model can react to instead of crashing
the run.
MCPStdioTransport/PersistentMCPSessionaliases are exported.
Polished documents — build_document
- Five formats — PDF reports, Excel workbooks, Word documents, PowerPoint
decks, and styled HTML from one structured payload (
title+sections, orsheetsfor Excel). - Finished, not generated — accent-colored headings, zebra-striped tables,
bold frozen header rows, auto-sized columns; Excel cells starting with
=become live formulas. - Optional dependencies — renderers use
reportlab/openpyxl/python-docx/python-pptxand reply with the exactpip installfix when one is missing; HTML needs nothing.
Clean tool-call logs — format_activity
- rich tool cards —
format_activity(result)renders each call as⚙ name(args) ✓ 228mswith a compact output preview and a run summary footer;format_event_line(event)does the same live for streams. - Timing built in — every
AgentEventnow carries atimestamp;tool_completed/tool_failedcarry the tool name andduration_ms.
Scheduled jobs — AgentScheduler
- Cron for agents —
sched.add(prompt, every=3600),at="09:00"daily, orcron="0 8 * * 1"(optionalcroniter);run_forever()fires jobs as they come due. - Durable jobs — pass
store=SQLiteJobStore()and due times + run counts persist across restarts; a re-added job resumes its slot instead of resetting. - Production niceties —
on_resultcallbacks,max_runscaps, session-backed runs, and injectableclock/sleepso schedules are unit-testable with zero real waiting.
MCP, deeper — resources, prompts, streamable HTTP
- Resources & prompts —
server.list_resources()/read_resource(uri)andlist_prompts()/get_prompt(name, args);server.resource_tool()gives the model a tool to browse/read a server's resources. Servers that don't implement them return empty lists, not errors. - Streamable HTTP transport —
MCPStreamableHTTPTransportspeaks the 2025 spec revision: JSON and SSE responses,Mcp-Session-Idaffinity, andbearer_token=on both HTTP transports for OAuth-protected servers.
Run metrics & live-updatable events
result.summary()— wall-clock duration, iterations, token usage, and a per-tool breakdown (calls / failures / total ms) in one dict.- Correlation ids —
tool_called/tool_completed/tool_failed/tool_retryshare acall_id, so live UIs can update one tool card in place (running → ✓/✗) instead of appending lines.
Background subagents & context compaction
- Parallel delegation —
sub_agentacceptsbackground=true(returns a task id immediately, runs on a thread pool) andcollect="task-N"to fetch the result — background task fan-out. - Observable compaction — when a run approaches the context window, older
turns are summarized (user/assistant content included, not dropped) and a
context_compactedevent reports before/after message counts.
See the Super agent guide for the full tour.
v1.0.14 — 2026-06-13
The SHIPIT Workspace — point an agent at a repo and it just works. v1.0.14
turns a repository into the agent's control surface: drop a few conventional
files and every agent rooted there picks them up — no glue code. Project
instructions, file-based /slash commands, and a checked-in permission/env
policy load automatically, and a new TodoTool keeps long runs observable.
None of it is provider-specific — it works with any LLM you pass.
Project memory — SHIPIT.md / AGENTS.md
- Auto-loaded instructions — a
SHIPIT.md(orAGENTS.md, or.shipit/SHIPIT.md) at the repo root is loaded into the system prompt for anyAgent(llm=llm, project_root="."). A user-global~/.shipit/SHIPIT.mdapplies everywhere; every matching file is included, project context first. @pathimports — instruction files pull in others with@relative/path(depth-limited, cycle-safe), resolved relative to the importing file.- Opt out / direct API —
auto_project_memory=Falseskips the injection;load_project_memory(project_root, ...)fromshipit_agent.workspacereturns the assembled block yourself.
Slash commands — .shipit/commands/
- File-based commands — drop
.shipit/commands/<name>.mdand runagent.run("/<name> ...args"); the body becomes the prompt with$ARGUMENTSand$1/$2substitution. Leading YAML frontmatter is stripped; unknown/cmdtext passes through unchanged.discover_commands()/expand_command()expose the same logic.
Settings — .shipit/settings.json
- Declarative policy — check
model,permissions(mode/allow/deny/ask), andenvinto the repo; a user-global~/.shipit/settings.jsonmerges underneath.load_settings()reads it andWorkspaceSettings.to_permission_engine()wires it into the control plane. Agent.for_project(llm=..., project_root="/repo")— one call that loads settings → permission engine, attaches builtin tools, and enables project memory +/slashcommands. Works with any LLM provider. See Agent → The SHIPIT Workspace.
TodoTool — live task tracking
- The SHIPIT TodoWrite — a live, replace-on-write checklist
(
todos:{content, status}withpending/in_progress/completed) the model maintains while it works, rendered as a glyph checklist and stored oncontext.state["todos"]with summary metadata. Included inAgent.with_builtins()(andfor_project), so long agentic runs stay observable. See Tools → TodoTool.
v1.0.12 — 2026-06-07
Claude API power — plus cross-provider prompt-cache accounting. v1.0.12 adds the Anthropic API's highest-leverage server features as first-class passthroughs — server-side tools, document citations, the Batch API, and interleaved thinking + server-side context editing — on top of v1.0.11's control plane. It also makes prompt caching honestly cross-provider: OpenAI's automatic cache reads are now surfaced for cost tracking. Each feature is honest about provider support; no public API was removed.
Server-side tools (Anthropic-hosted)
web_search(),code_execution(),computer_use(),bash(),text_editor()fromshipit_agent.llms— declare them in thetools=list you pass toAnthropicChatLLM.complete(...)(mixed freely with client-side tools). They run inside Anthropic's own sandbox — zero local infrastructure, no client-side tool loop.- Beta headers handled automatically —
code_executionandcomputer_useattach their betas and route to the beta endpoint;web_searchis GA and stays on the GA endpoint. - Surfaces in metadata —
LLMResponse.metadata["server_tool_use"]and["server_tool_results"], only when present. - Provider note — these are Anthropic API shapes (also reachable for Anthropic models via Bedrock / LiteLLM); other providers use their own native server tools. See Agent → Server-side tools.
Citations & the Batch API
- Citation document helpers —
text_document/pdf_document/url_pdf_document/content_documentfromshipit_agent.llms, withcitations.enabledon by default. Claude grounds its answer in the document and the cited spans are parsed intometadata["citations"]— verifiable RAG. - Batch API runtime —
BatchRequest,BatchResult, andBatchRuntime.run(...)(inshipit_agent.batch) wrap Anthropic's Messages Batches API for bulk, latency-tolerant runs at roughly 50% of standard per-token price.submit/status/results/cancelare exposed too. - Provider note — Anthropic citations and Anthropic batches today; OpenAI also has a Batch API and generalising the runtime is on the roadmap. See Agent → Citations & Batch API.
Interleaved thinking & context editing
AnthropicChatLLM(interleaved_thinking=True, thinking_budget_tokens=…)— the model thinks between tool calls. Theinterleaved-thinking-2025-05-14beta attaches only when both are set;metadata["thinking_blocks"]carries the signed thinking blocks for round-tripping.context_management=— forwarded as Anthropic'scontext_managementrequest param (with its beta header) so the API clears stale tool results server-side.- Provider note — extended / interleaved thinking is Anthropic; OpenAI reasoning models and Gemini thinking are the equivalents elsewhere (reasoning content is captured for all of them). See Agent → Interleaved thinking & context editing.
Cross-provider prompt caching
- OpenAI cached-token surfacing — OpenAI does automatic prompt caching;
shipit now reads
usage.prompt_tokens_details.cached_tokensintousage["cache_read_input_tokens"]— the same key theCostTrackerreads for Anthropic — so OpenAI cache reads bill at the cheaper rate.LiteLLMChatLLMforwards both shapes. Anthropic / Bedrock / Vertex keep explicitcache_controlbreakpoints (default on for Claude). Caching is cross-provider, not Anthropic-only. See Agent → Prompt caching.
v1.0.11 — 2026-06-07
A control plane for tool calls — plus prompt caching and a memory tool. v1.0.11 brings a full permission layer to the library: declarative allow/deny/ask rules, read-only plan mode, human-in-the-loop callbacks, and blocking/rewriting hooks. It also turns on Anthropic prompt caching by default for Claude-family models and adds an Anthropic-style memory tool. Folded in is the 1.0.10 bug-fix & hardening work. No public API was removed.
Control plane — permissions, plan mode & hooks
Agent(permission_mode=...)—"default","acceptEdits","plan", or"bypass",planmakes a run read-only;acceptEditsauto-approves file edits.PermissionEngine(allow=[...], deny=[...], ask=[...])—fnmatchglobs on tool name with a predictable precedence: deny > mode > allow > ask > callback > default. Pass it aspermissions=(also accepts a bare mode string or a kwargs dict).agent.plan(prompt)— one-call read-only planning: the agent may use read-only tools and writes a step-by-step plan instead of acting.permission_callback(name, args) -> PermissionResult | None— programmatic human-in-the-loop approval, consulted onaskrules and as a catch-all.- Blocking & rewriting hooks —
@hooks.on_before_toolmay return{"decision": "deny"}to block a call or aPermissionResultwithupdated_argumentsto rewrite it;@hooks.on_user_promptcan redact the incoming prompt. Hooks remain observe-only when they returnNone. - Denied calls are visible — a blocked tool emits a
tool_deniedevent and feeds the model awas NOT runtool message so it can recover. - New top-level exports:
PermissionEngine,PermissionResult,PermissionDecision. See Agent → Permissions, plan mode & blocking hooks.
Prompt caching
- On by default for Claude-family models.
AnthropicChatLLM(prompt_caching=True)andLiteLLMChatLLM(prompt_caching=True)cache the stable prefix (system prompt + tools) on Anthropic, Bedrock, and Vertex viacache_controlbreakpoints. - Cost-aware —
usage["cache_read_input_tokens"]andusage["cache_creation_input_tokens"]flow intoCostTracker; cache reads bill at roughly 10% of input. See Agent → Prompt caching.
Claude-style memory tool
ClaudeMemoryTool— Anthropic'smemory_20250818tool shape: a single command-driven tool (view/create/str_replace/insert/delete/rename) over a sandboxed memory directory (.shipit_workspace/memoriesby default) for cross-session learning. Attach viaAgent(tools=[ClaudeMemoryTool(...)]). See Tools → Claude-style memory tool.
Hardening (folded in from 1.0.10)
text_delta_callbackregression (v1.0.9) fixed — the runtime now inspects the adapter signature and only passes the callback to adapters that accept it, so every custom adapter works unchanged.- Multi-turn sessions no longer stack duplicate system prompts when reusing
a
session_store+session_id. - Tool security — Bash rejects command/process substitution and redirection;
open_urlis http(s)-only and blocks SSRF targets; the SQL read-only guard scans the whole statement and rejects stacked statements; OAuth validates the CSRF state nonce;edit_filerefuses non-UTF-8 files;FileCredentialStorechmods0600and writes atomically. - Reliability — MCP transports close on error; parallel tools get isolated
state; the iteration-cap turn is now accounted for;
CostTrackerflagshas_unknown_pricinginstead of silently billing$0. - 1742 tests passing (+180 new). 0 regressions.
v1.0.9 — 2026-05-14
Inline text streaming + multimodal media references. Two features that make shipit feel live in chat UIs: token-by-token text streaming for real-time typing, and first-class image/file references in prompts.
Inline text streaming
LLM.complete(text_delta_callback=…)— stream assistant text token-by-token as it's generated, instead of waiting for the full response. The callback fires for each incremental text chunk.AgentRuntimeemitstext_deltaevents — drive SSE or WebSocket consumers directly from the event stream for ChatGPT-style live typing in the browser.- Non-streaming behavior preserved — streaming is opt-in per call; omit the
callback and
complete()behaves exactly as before. - Implemented end-to-end for LiteLLM, and no-op-compatible for the other adapters (they return the full text in a single delta), so nothing breaks if a backend can't stream.
Multimodal media references
MediaReference— reference an image or file inside a prompt without inlining bytes; the runtime resolves it at send time.MediaStore— pluggable storage for media, withInMemoryMediaStorefor tests and short-lived runs andFileMediaStorefor on-disk persistence.extract_media_refs+build_multimodal_message— pull media references out of a prompt and assemble the provider-native multimodal message payload.- See Agent → Multimodal chat.
v1.0.8 — 2026-05-09
Structured output overhaul + verifier network. Two flagship features that genuinely beat LangChain on the surfaces it tries hardest at — and ship more broadly applicable wins than v1.0.7's connector explosion.
Structured output — same-conversation validation retry
Agent.run(prompt, output_schema=MyModel, max_validation_retries=2)— pass a Pydantic model or JSON Schema dict; get back a typedresult.parsed.- Auto-retry on validation failure inside the same conversation — when the
first parse fails, the runtime appends the bad assistant turn + a corrective
user turn ("that response could not be parsed: …") and retries. No separate
"fixing LLM" call (LangChain's
OutputFixingParserrequires one). - Streaming partial JSON parser —
parse_partial_json('{"a": "hel')returns{"a": "hel"}.StructuredOutput.stream(prompt)yields progressively richer dicts as tokens arrive, then a final validated typed object. StructuredOutput— standalone wrapper for one-shot extraction without the agent loop; same retry path, exposed publicly.- New top-level exports:
StructuredOutput,StructuredOutputResult,parse_partial_json. Newresult.parsedandresult.outputcorrected text semantics onAgent.run. - See Agent → Structured output.
Verifier network — process supervision
Agent(verifier=VerifierNetwork(llm=cheap_llm))— a second cheap LLM vetoes hallucinated tool calls before they fire and rates progress between iterations. Both checks fail open (verifier failures never block the agent).- Pre-tool veto — wraps every tool. Verifier returns
allow | veto | rewrite; vetoed calls become synthetic error tool-results so the agent re-plans without the bad action having actually run. - Progress check — after each iteration, scores progress 0-1. When the
score stays below
progress_thresholdforprogress_windowconsecutive iterations,maybe_nudge()returns a "you're stalling" message you can inject as a user turn. - Confidence-gated — verdicts below
veto_min_confidenceget downgraded toALLOW(avoid over-blocking on uncertain calls). - Hard caps —
max_pretool_calls_per_run,max_progress_calls_per_runso the verifier itself can't run away on cost. - Telemetry —
verifier.statsexposes per-run counters: vetoes, rewrites, nudges, score history. - LangGraph's
ToolNodehas no per-call gating. LangChain'sRunnableWithMessageHistoryhas no progress detector. Process supervision in shipit is one constructor argument. - See Agent → Verifier network.
Episodic memory consolidation
MemoryConsolidator(llm=cheap_llm).consolidate(memory=..., recent_messages=...)— LLM distills the last conversation into 3-8 durable facts and writes them toSemanticMemory. Categories (preference,project,goal,person,other) are tracked for filtering.- Forgetting curve —
consolidator.decay(knowledge, half_life_days=14)applies exponential decay to fact strength and prunes facts belowforgetting_threshold. Pure local arithmetic; no LLM call. - Core memory —
consolidator.core_memory(knowledge, top_k=5)returns the top-K most-load-bearing facts ranked bystrength + 0.1·log1p(retrievals). Inject into the system prompt every turn for ChatGPT-style "remembers things across sessions". - Retrieval bumping —
consolidator.record_retrieval(knowledge, [fact_texts])increments retrieval counts. Frequently-retrieved facts rise to core memory automatically. - New top-level exports:
MemoryConsolidator,DistilledFact,ConsolidationResult. - ChatGPT's Memories feature is
add_fact(text)with no decay, no retrieval-based promotion. Ours is principled and self-hostable. - See Agent → Episodic memory consolidation.
Time-travel replay
TraceReplayer.from_store(store, trace_id)— load any saved trace and walk events programmatically. Three constructors:from_record,from_store,from_file.replayer.fork(at_event=N, edit_user_message='...')— capture the conversation state at any event, optionally with a tweaked user prompt. Returns aReplayCheckpoint.checkpoint.continue_from(agent=fresh_agent)— resume the run on a freshAgent, withagent.historypre-filled. Forwards arbitraryAgent.runkwargs (e.g.output_schema=).diff_traces(left, right)— side-by-side comparison. Reports matched events, divergence point, type mismatches, and only-in-left / only-in-right tails..to_lines()for human-readable rendering.- New top-level exports:
TraceReplayer,ReplayCheckpoint,ReplayResult,ForkPoint,TraceDiff,diff_traces. - LangSmith's Playground is SaaS-only. Inngest's branching is SaaS-only.
Ours is library-level, open-source, and works against your existing
FileTraceStore. - See Agent → Time-travel replay.
ComputerUseAgent — browser automation
ComputerUseAgent(llm=, browser=, goal=)— screenshot → reason → act loop. Show a screenshot to a vision-capable LLM, parse a structured action back, execute, repeat until DONE.PlaywrightBrowserSession.launch(headless=True)— production driver. Context-manager support;pip install playwright && playwright install chromiumto enable.MockBrowserSession— deterministic test double that records every call. Unit-test computer-use logic without spawning a browser.- Two action emit shapes — Anthropic's native
computer-usetool (structuredtool_useblock) AND plain-text fallback (ACTION: click 100,200) for any vision LLM. parse_action(raw)— pure parser, no IO. Handles both shapes plus prose-wrapped responses.- Recovery — when an action raises, the agent surfaces the error back to the model as a user message. Production-ready resilience without extra code.
- New top-level exports:
ComputerUseAgent,BrowserSession,MockBrowserSession,PlaywrightBrowserSession,ComputerAction,ComputerUseResult,ActionKind,ActionRecord,parse_action. - Devin / Multi-On / OpenAI Operator are SaaS products. Ours is a library — self-host, plug into your own loop, fork the implementation.
- See Agent → ComputerUseAgent.
Tests + docs
- +318 unit tests (1190 → 1508), zero regressions, all old tests still pass.
- Five new notebooks —
54_structured_output_with_retry.ipynb,55_verifier_network.ipynb,56_episodic_memory_consolidation.ipynb,57_time_travel_replay.ipynb,58_computer_use_agent.ipynb. - Five new docs pages with full API reference, configuration deep dives, cost analysis, real-life examples, and beat-LangChain / Operator / ChatGPT comparison tables.
v1.0.7 — 2026-04-24
Agents for every role. Twelve new tools, nine new persona specialists, seven persona walk-through notebooks. shipit-agent is no longer only a developer-agent framework — it ships agents for developers, designers, sales reps, PMs, data analysts, finance, customer support, and recruiters. 1190 unit tests, 286 new in this release, zero regressions.
See RELEASE_NOTES_1.0.7.md for the full breakdown.
v1.0.6 — 2026-04-21
Autopilot — the long-running runtime. Plus 7 new role specialists, 3 new tools, and 8 new notebooks. Autopilot turns any agent into a budget-gated, checkpointed, streaming worker that runs until every success criterion is met. Fan-out dispatches N children in parallel. A reflection critic short-circuits the loop once a confident reviewer confirms the goal. Artifacts capture code blocks, markdown docs, and tool outputs as structured deliverables. A scheduler daemon drains a persistent JSON queue for 24-hour operation. 8 new Bedrock-Llama notebooks. 805 total tests. All passing.
Autopilot — long-running runtime
Autopilot(llm, goal, budget, …)— composesGoalAgentwith budget gates, atomic checkpoints, heartbeats, and a live event stream.BudgetPolicy(max_seconds, max_tool_calls, max_tokens, max_dollars, max_iterations)— every axis independently honored; set any toNone/0to disable.- Goal-satisfaction termination, not step count. Stops the moment every criterion is verified OR any budget trips.
- Atomic JSON checkpoints per iteration —
~/.shipit_agent/checkpoints/<run_id>.json. Crash →autopilot.resume(run_id)picks up at the next iteration. autopilot.stream(run_id)— iterator of{kind, ...}events:autopilot.run_started,autopilot.iteration,autopilot.heartbeat,autopilot.criteria_satisfied,autopilot.budget_exceeded,autopilot.result.default_heartbeat_stderr— drop-in sink. Custom callables (Slack / Datadog / webhook) just as easy.
Reflection critic
Critic(llm=..., confidence_threshold=0.75)— scores every iteration's output against the goal's criteria and feeds suggestions into the next iteration's prompt.critic=Trueon Autopilot to use your run's LLM as a self-check; pass aCritic(llm=reviewer_llm)for a dedicated stronger reviewer.- Confidence-gated termination — flag-flips only count when the critic meets the confidence gate. Low-confidence "yes" still logs feedback but does not halt.
- JSON-tolerant parsing — handles fenced
```json, extra prose, padding/trimming of criteria, and garbage input without raising. - New event kind
autopilot.criticon every iteration's stream.
Artifacts — structured deliverables
ArtifactCollector— collectsArtifact(kind, name, content, language, iteration)during the run.- Auto-extraction from every iteration's output — fenced code blocks (
kind="code", with language) and top-level markdown docs (kind="markdown"). - Tool-metadata ingestion — tools that declare
{"artifact": True, "kind": ..., "name": ..., "content": ...}in their result metadata are captured explicitly. - Optional disk persistence — one JSON file per artifact, handy for CI build outputs.
- New event kind
autopilot.artifact; finalAutopilotResult.artifactscarries the full list.
Parallel fan-out
autopilot.fanout(items, objective_template, criteria_template, max_parallel, child_budget_frac)— ThreadPoolExecutor-backed N-way parallelism.- Per-child budget scaling — each child inherits
parent_budget * child_budget_frac(default 20%). Keeps aggregate spend bounded on 50-item batches. autopilot.fanout_stream()— live per-child events (autopilot.fanout_child) for dashboard rendering.FanoutResult(children, aggregated_output, wall_seconds, failed)— rolled-up status (completed|partial|failed), ordered children, default markdown digest or customaggregator.
Scheduler daemon
SchedulerDaemon(llm_factory, queue_path, tick_seconds)— persistent JSON goal queue at~/.shipit_agent/autopilot-queue.json.enqueue(),list_queue(),remove(),run_once(),run_forever(). Stateless daemon; crash-safe.- Heartbeat events on idle so you can wire Slack / Datadog telemetry.
- CLI:
shipit autopilot,shipit daemon,shipit queue {add,list,remove}. Systemd / launchd / Docker recipes in the docs.
7 new role specialists
- Engineering —
generalist-developer,debugger - Design —
design-reviewer - Product —
product-manager - Go-to-market —
sales-outreach,customer-success,marketing-writer - Auto-applied to
agents.jsonon import — 40 → 47 specialists total.
3 new power tools
computer_use— drive the local desktop (screenshots, click, type, drag, key chords). Platform backends for macOS (cliclick/osascript), Linux (xdotool/scrot), Windows (PowerShell). Graceful install hints when a dep is missing.hubspot_ops— HubSpot CRM v3 REST wrapper. Search / get / create contacts, companies, deals; attach notes. Auth viaHUBSPOT_TOKENenv.research_brief— one-call research primitive. Web search + top-page skim + numbered citations. No API key (DuckDuckGo HTML). Optionaldeep=Truefetches each source page for richer summaries.
Notebooks — 37 through 44
- 37 — Autopilot quickstart.
- 38 — Live streaming (
autopilot.stream(),render_stream, custom heartbeats). - 39 — Persistence, resume, scheduler daemon.
- 40 — Developer / Debugger / Researcher specialists.
- 41 — Design / PM / Sales / CS / Marketing specialists.
- 42 —
computer_use/hubspot_ops/research_brieftools. - 43 — Fan-out · Critic · Artifacts.
- 44 — The Complete Tour — every feature end-to-end in one notebook.
All notebooks use build_llm_from_env("bedrock") — default is Bedrock Llama 4 Scout, matches the 01–36 series.
Other changes
AutopilotResultgrewartifacts: list[dict]andcritic_verdict: dict. Existing fields unchanged.Autopilotacceptscritic=True | Critic(...)andartifacts=True | ArtifactCollector(...).- Fan-out helpers (
_scale_budget,_slug,_rollup_status) are pure functions — re-use them in your own dispatchers. - 39 new tests (
test_autopilot_artifacts.py,test_autopilot_critic.py,test_autopilot_fanout.py).
Second half — CostRouter, non-blocking ask_user, vision, sandbox, specialists-as-developers
The second half of v1.0.6 adds four more primitives that compose with Autopilot and an overhaul of the specialist tool presets so every role can actually execute code.
CostRouter — tiered LLM routing
shipit_agent.routing.CostRouter— drop-in LLM adapter that classifies each turn aseasy/medium/hardand routes to the cheapest adequate model.- Heuristic classifier (
classify_difficulty) with no extra LLM call — hard-keyword list + length thresholds + code-fence detection, tuned from real agent traces. Passdifficulty_fn=...to swap in your own oracle. Tier(llm, price_per_1k, name)— wrap any shipit_agent LLM; price only drives the report, never the routing decision.SpendReport— tier counts, estimated spend, "would-have-been" spend on hardest tier, andsavings_pct. Populated live as the runtime callscomplete()/stream().force_tier=DifficultyTier.HARDfor audits; fallback to MEDIUM when a classifier raises. Runs never die on classification errors.- Typical savings on 24h runs: 50–70%.
Non-blocking ask_user_async
- New tool
ask_user_asyncpauses an Autopilot run cleanly — does not block the loop. - File-based side channel at
~/.shipit_agent/askuser/<run_id>.json. Atomic rename on every write; crash-safe. Autopilotintegration — on every iteration, if a question is pending on the channel, the run halts with new statusawaiting_user.resume()returns immediately while the channel is still pending; once answered, the loop continues.shipit answer <run_id> "..."— CLI to reply.--index Ntargets a specific question; runningshipit answer <run_id>with no text lists pending + answered history.- Multiple outstanding questions are supported;
write_answertargets the latest by default. SHIPIT_ASKUSER_DIRenv redirects the channel (useful for tests and containerized runs).- Safe against path traversal —
run_idis slugged before becoming a filename.
Vision feedback on computer_use
- Every
screenshotaction now embeds the PNG's base64 bytes +media_typein result metadata, so a vision-capable LLM can actually reason over the captured image instead of just reading a file path. - 4 MB cap — larger PNGs set
vision=False+ avision_skip_reason; no context-window blow-ups. - Opt-out via
vision=Falsekwarg on the tool call. - Read errors surface in
vision_skip_reasonrather than raising.
Docker sandbox on code_execution
sandbox=Trueonrun_coderuns the snippet inside an ephemeral container with--network none, a--read-onlyroot filesystem, and a writable 64 MB/tmptmpfs.network=Trueopts back into bridge networking (rarely needed — isolation is the point).image=...overrides the per-language default image.- Default images:
python:3.11-slim,node:22-alpine,ruby:3.3-alpine,alpine:3.20for shells, plus typescript / php / perl / lua / r. Override viaSANDBOX_IMAGES. - Workspace mounted read-only at
/work; snippet can read but not modify host files. workspace_rootkwarg points the tool at any user-chosen directory — per-call override of the shared default. Works in both sandbox and non-sandbox modes.- Graceful fallback when Docker isn't installed — returns
metadata={"ok": False, ...}+ a clear install hint. Runs never crash.
Specialists that run + test code
- All seven role specialists (
generalist-developer,debugger,design-reviewer,product-manager,sales-outreach,customer-success,marketing-writer) now ship withrun_code+ask_user_asyncin their tool list. - Developer + debugger also keep
bash+run_tests; designer gainscomputer_use; PM + sales + marketing gainresearch_brief; CS keepshubspot_ops+gmail+slack. - Every
run_codecall acceptsworkspace_rootso the user points the specialist at their project.
Notebook 45 + 3 new doc pages
- Notebook 45 — 34 cells —
45_cost_router_async_ask_vision_sandbox.ipynb. Covers routing, async ask, vision, sandbox, workspace override, composed live streaming (critic + artifacts + router together), JSONL stream, parallel fan-out stream, and a specialist-as-developer example. routing/cost-router.md— full CostRouter guide, custom classifier recipe,force_tieroverride,SpendReportschema.autopilot/ask-user-async.md— side-channel anatomy, CLI + programmatic answer path, prompt-design rules.tools/code-execution-sandbox.md— per-language image table,workspace_rootuse case, Docker-missing fallback.tools/computer-use.md— new "Vision feedback" section with themetadata["vision"]contract and opt-out.
Tests
- 58 new tests (27
test_cost_router.py, 14test_askuser_async.py, 5test_computer_use_vision.py, 12test_code_execution_sandbox.py). - Grand total: 863 tests, 0 failures.
New / changed public surface
| Symbol | Where |
|---|---|
CostRouter, Tier, SpendReport, DifficultyTier, classify_difficulty | shipit_agent.routing |
ask_question, write_answer, pending_questions, all_entries, channel_file, channel_dir, clear | shipit_agent.askuser_channel |
AskUserAsyncTool | shipit_agent.tools.ask_user_async |
AutopilotResult.status == "awaiting_user" | shipit_agent.autopilot.result |
CodeExecutionTool.run(..., sandbox=True, network=True, image="...", workspace_root="...") | shipit_agent.tools.code_execution |
build_sandbox_command, SANDBOX_IMAGES, SANDBOX_CMDS | shipit_agent.tools.code_execution.sandbox |
ComputerUseTool.run(..., vision=False) + metadata["vision"/"image_base64"/"media_type"] | shipit_agent.tools.computer_use |
shipit answer <run_id> [text] [--index N] | CLI subcommand |
v1.0.5 — 2026-04-18
Prebuilt agents, multi-agent crews, notifications, and cost tracking. 40 ready-to-use agent personas across 8 categories. DAG-based ShipCrew orchestration with sequential, parallel, and hierarchical modes. Slack, Discord, and Telegram notification hub. Real-time cost tracking with budget enforcement. 4 new notebooks, 4 new doc pages, 153 new tests. 706 total tests. All passing.
Prebuilt Agents — 40 Ready-to-Use Personas
shipit_agent.agentsmodule —AgentDefinitiondataclass +AgentRegistryfor loading, searching, and composing agent personas.- 40 agents across 8 categories: Architecture (5), Code Quality (6), Security (5), DevOps (5), Testing (5), Planning (4), Research (5), Content (5).
AgentRegistry.default()— loads in one line. Search, browse by category, merge with project-local agents..shipit/agents/override — drop JSON files in your project; they override built-in agents with the same ID.
ShipCrew — Multi-Agent Crew Orchestration
ShipCrew,ShipAgent,ShipTask— DAG-based multi-agent crews with task dependencies.- Three execution modes:
sequential,parallel(ThreadPoolExecutor),hierarchical(LLM-driven assignment + review). - Template variable resolution —
{output_key}in descriptions auto-resolves from upstream outputs. ShipAgent.from_registry()— load crew agents from the prebuilt registry.- Streaming —
crew.stream()yields events for crew start, task start/complete/fail, crew complete. - Validation — cycle detection (Kahn's algorithm), missing agent checks, unknown dependency warnings.
Notification Hub — Slack, Discord & Telegram
SlackNotifier— Block Kit webhooks with color-coded severity. Zero external deps.DiscordNotifier— rich embeds with inline metadata fields.TelegramNotifier— Bot API with MarkdownV2 and auto-escaped special characters.NotificationManager— multi-channel dispatch withmin_severityandeventsfiltering.manager.as_hooks()— auto-notify on agent lifecycle events.
Cost Tracking & Budgets
CostTracker— real-time per-call cost tracking with 20+ model pricing table.Budget(max_dollars=5.00)— enforcement withBudgetExceededErrorandon_cost_alertcallback.tracker.as_hooks()— automatic cost tracking from every LLM call.- Model aliases —
"opus","sonnet","haiku"resolve to full model IDs.
Notebooks, Docs & Tests
- 4 notebooks: Prebuilt Agents (25 cells), ShipCrew (25 cells), Notifications (27 cells), Cost Tracking (31 cells).
- 4 doc pages:
guides/prebuilt-agents.md,deep-agents/ship-crew.md,guides/notifications.md,guides/cost-tracking.md. - 153 new tests (553 → 706 total). 29 new source files.
v1.0.4 — 2026-04-12
Skills, tools, and runtime power-up. All 32 tool prompts rewritten with decision trees and anti-patterns. Full skill-to-tool linking for all 37 packaged skills. Automatic iteration boost for skill-driven workflows. Expanded bash allowlist (50+ commands). Streaming, chat, and project-building examples across 3 notebooks. Comprehensive docstrings across every key module. 32 skill tests. All passing.
Skills — Full Tool Linking
- 37 skill tool bundles (up from 10) — every packaged skill now declares the built-in tools it needs. When a skill is selected, the agent auto-attaches the right tools.
- Shared tool groups (
_FILE_CORE,_CODE_CORE,_WEB_CORE) reduce duplication across bundles. validate_tool_bundles()— new helper that checks every tool name inSKILL_TOOL_BUNDLESagainst the real builtin map.
Agent — Iteration Boost & Efficiency
_effective_max_iterations()— auto-boosts 4 → 8 when skills inject extra tools so skill-driven workflows can complete without cutting off early.- Single skill computation —
run()andstream()now compute skills once and reuse (previously 3x per call).
Tool Prompts — All 32 Upgraded
Every tool's prompt.py rewritten with decision trees, anti-patterns, workflow guidance, and cross-tool coordination.
Bash Allowlist Expansion
- 50+ safe commands added:
mkdir,touch,cp,mv,echo,grep,curl,docker,kubectl,terraform,aws,go,cargo,npx,tsc,eslint,black,isort,tree,awk,cut,diff, and more.
Documentation
- Comprehensive docstrings on
agent.py,builtins.py,skills/loader.py,skills/registry.py,skills/tool_bundles.py,deep_agent/factory.py. - 6 tool doc pages updated with enhanced prompts.
- Skills guide expanded with 7 real-world examples, streaming sections, chat sessions, and event type reference.
- Notebook 27 rewritten (38 cells): streaming, chat streaming, project build, web scraping, DeepAgent chat.
- Notebook 29 (new): DeepAgent + skills + memory + verify + reflect + sub-agents + streaming.
- Notebook 30 (new): real-world full project build across 6 steps with 5 different skills.
Tests
- 15 new tests (17 → 32 total): iteration boost, bundle validation, chat sessions, streaming, chat streaming, memory + skills, DeepAgent chat/stream.
v1.0.3 — 2026-04-11
Major feature release. Super RAG subsystem, DeepAgent factory (verify / reflect / goal / sub-agents), live multi-agent chat REPL (shipit chat), Agent memory cookbook, plus deep docs + notebook coverage. 521 unit tests. 19 Bedrock end-to-end smoke tests. All passing.
Super RAG
shipit_agent.ragsubsystem — pluggable chunker + embedder + vector store + keyword store + hybrid pipeline (vector + BM25 + RRF + recency bias + rerank + context expansion).rag=on every agent type — auto-wiresrag_search/rag_fetch_chunk/rag_list_sourcestools, augments the system prompt with citation instructions, and attachesresult.rag_sourceswith stable[N]citation indices.- Adapters —
DrkCacheVectorStore(pgvector over psycopg2) + lazy Chroma / Qdrant / pgvector. - Thread-local per-run source tracker so concurrent runs never leak citations.
DeepAgent
shipit_agent.deep.DeepAgent— power-user factory bundling seven deep tools:plan_task,decompose_problem,workspace_files,sub_agent,synthesize_evidence,decision_matrix,verify_output. Guide- One-flag power features:
verify=True,reflect=True,goal=Goal(...),rag=RAG(...),memory=AgentMemory(...). agents=sub-agent delegation — plug any mix of agent types as named delegates via a built-indelegate_to_agenttool.create_deep_agent()functional helper — auto-wraps plain Python callables as tools.- Nested event streaming — sub-agent events surface inside
tool_completed.metadata['events'].
Live chat REPL
shipit chat— modern multi-agent terminal REPL. Switch agent types live, index files mid-session, save/load conversations, togglereflect/verify, inspect tools and sources. Guide- Rich slash commands:
/agent,/agents,/tools,/sources,/index,/rag,/goal,/reflect,/verify,/history,/save,/load,/reset,/info, … - Pluggable LLM provider via
--provider; persistent sessions via--session-dir.
Streaming
DeepAgent.stream()covers every execution mode (direct, verified, reflective, goal-driven, sub-agent delegation).PersistentAgent.stream()added with per-step checkpointing.rag_sourcesevent type added — emitted after every RAG-backed run.
Memory
- Dedicated Agent → Memory cookbook explaining the two memory systems (
memory_store=for the LLM'smemorytool vsAgentMemoryfor application-curated profiles). Guide - DeepAgent auto-hydration —
memory=AgentMemory(...)seeds the inner agent'shistoryfrom the conversation summary. - Notebook 26 — runnable end-to-end tour.
Docs
- New Agent section (6 pages): Overview, Examples, Streaming, With RAG, With Tools, Memory, Sessions.
- New Super RAG section (6 pages): Overview, Standalone, Files & Chunks, With Agent, With Deep Agents, Adapters, API.
- New DeepAgent page. Reference
- Parameters Reference — every constructor parameter for every agent type and key class. Reference
- Updated Architecture + Model Adapters reference pages.
- Updated quickstart with Agent / Deep Agent / RAG sections.
- Updated FAQ with "Agent types — which one should I use?".
- 5 new notebooks (22–26): RAG basics, RAG + Agent, RAG + Deep Agents, DeepAgent chat, Agent memory.
- Full-width docs layout + collapsible TOC with floating toggle, persistence via localStorage.
Build
shipit-chatscript entry point.- Granular extras:
rag,rag-openai,rag-cohere,rag-chroma,rag-qdrant,rag-pgvector,rag-drk-cache,rag-pdf,rag-docx,rag-rerank-cohere,rag-rerank-cross-encoder, plusbedrock,google,groq,together,ollama. Theallextra bundles everything.
Fixed
- Tool schema format bug —
RAGSearchTool,RAGFetchChunkTool,RAGListSourcesTool,WebhookPayloadToolnow use the wrapped{"type": "function", "function": {...}}shape. Previously they were returning flat dicts and Bedrock's Converse API was rejecting them with empty-name validation errors. New regression test scans every tool for Bedrock compatibility. memory=AgentMemorytype coercion —DeepAgentandGoalAgentno longer auto-assignAgentMemory.knowledge(aSemanticMemory) intomemory_store=(which expects aMemoryStore).memory=now only seedshistory; users passmemory_store=explicitly for the runtime'smemorytool.Agent.with_builtins(tools=[...])keyword collision — the method now accepts and merges usertools=with the builtin catalogue (last-write-wins on name collision).AgentDelegationToolstreaming — uses inner agent'sstream()and packs events intotool_completed.metadata['events'].
Test coverage
- 521 unit tests (up from 285) — green.
- 19 end-to-end Bedrock smoke tests in
scripts/smoke_bedrock_e2e.pycover every public surface end-to-end against real Bedrock.
v1.0.2 — 2026-04-10
Major feature release. Deep agents, structured output, pipelines, agent teams, advanced memory, output parsers, and runtime power features. 285 tests. 12 examples. 8 notebooks. 13 new doc pages.
Deep Agents
- GoalAgent — Autonomous goal decomposition with success criteria, streaming, and
.with_builtins(). Guide - ReflectiveAgent — Self-evaluation with quality scores and revision loop. Guide
- Supervisor / Worker — Hierarchical delegation with quality review. Guide
- AdaptiveAgent — Runtime tool creation from Python code. Guide
- PersistentAgent — Checkpoint and resume across sessions. Guide
- Channel / AgentMessage — Typed agent-to-agent communication. Guide
- AgentBenchmark — Systematic agent testing framework. Guide
- Deep Agents API Reference — Full constructor, method, and return type docs. Reference
Structured Output & Parsers
output_schemaon Agent.run() — Pydantic models + JSON schemas. Guide- JSONParser, PydanticParser, RegexParser, MarkdownParser. Guide
Composition
- Pipeline — Sequential, parallel, conditional, function steps, streaming. Guide
- AgentTeam — LLM-routed multi-agent coordination with streaming. Guide
Advanced Memory
- ConversationMemory — buffer/window/summary/token strategies. Guide
- SemanticMemory — Embedding-based vector search. Guide
- EntityMemory — Track people, projects, concepts. Guide
- AgentMemory — Unified interface with
.default(). Guide
Runtime Power Features
- Parallel tool execution. Guide
- Graceful tool failure. Guide
- Context window management. Guide
- Hooks & middleware. Guide
- Mid-run re-planning. Guide
- Async runtime. Guide
- Transient error auto-retry (429/500/503).
Changed
- Selective memory storage (breaking) — Only
persist=Truetool results stored. - Safer retry defaults —
(ConnectionError, TimeoutError, OSError)instead of(Exception,).
v1.0.1 — 2026-04-09
Maintenance release. Bug fix in the tool runner plus repo hygiene, contributor experience, and CI hardening. Strongly recommended upgrade from 1.0.0 if you use Bedrock gpt-oss-120b.
Fixed
ToolRunnerargument collision — FixedTypeError: got multiple values for argument 'context'when an LLM (notablybedrock/openai.gpt-oss-120b-1:0) emitscontextas a tool-call argument. The runner now strips reserved argument names (context,self) from tool-call arguments before forwarding. Affects every built-in tool.
Added
CHANGELOG.mdat repo root in Keep a Changelog formatCONTRIBUTING.mdwith dev setup, commit conventions, PR checklist, and "how to add a new LLM adapter / tool" guides- GitHub issue templates — structured bug report, feature request, and config forms
- PR template with 12-item verification checklist
- Test CI —
pytest -qon Python 3.11 + 3.12 × Ubuntu + macOS (4 matrix cells), with smoke-test of all 11 LLM adapter imports - Gitleaks secret scanning CI with SARIF upload to GitHub Security tab, inline PR comments, Actions summary
- Pre-commit hooks — trailing whitespace, EOF fixer, YAML/TOML validation, gitleaks v8.21.2, ruff lint + format
- Gitleaks allowlist for runtime tool outputs (scraped HTML contains false-positive "API keys" like Pushly domainKeys)
Changed
.gitignorerewritten to dedupe entries and cover all runtime directories (site/,.eggs/,pip-wheel-metadata/)- Runtime tool outputs untracked from git (
sessions/,traces/,memory.json,.shipit_notebooks/**) — they were accidentally committed in 1.0.0
Security
- Added CI and pre-commit secret scanning to prevent future credential leaks
- No runtime code changed —
shipit_agent/module is byte-identical to 1.0.0
v1.0.0 — 2026-04-09
First stable release. Focused on making the agent loop observable, interchangeable, and out of the way.
🧠 Live reasoning / thinking events
LLMResponse.reasoning_contentfield added to carry thinking/reasoning blocks from any provider- New
_extract_reasoning()helper handles three shapes:- Flat
reasoning_contenton the response message (OpenAI o-series,gpt-oss, DeepSeek R1, Anthropic via LiteLLM) - Anthropic
thinking_blocks[*].thinking(Claude extended thinking) model_dump()fallback for pydantic dumps
- Flat
- Runtime emits
reasoning_started+reasoning_completedevents whenever reasoning content is non-empty - All three LLM adapters —
OpenAIChatLLM,AnthropicChatLLM,LiteLLMChatLLM/BedrockChatLLM— share the extraction helper OpenAIChatLLMauto-passesreasoning_effort="medium"for reasoning-capable models (o1*,o3*,o4*,gpt-5*,deepseek-r1*)AnthropicChatLLMsupportsthinking_budget_tokens=Nto enable Claude extended thinking
⚡ Truly incremental streaming
agent.stream()now runs the agent on a background daemon thread- Events are pushed through a thread-safe
queue.Queueas they're emitted - Consumer loop yields events the instant they happen — no buffering, no batched delivery
- Worker exceptions are captured and re-raised on the consumer thread
- Works in Jupyter, VS Code, JupyterLab, WebSocket/SSE transports, and plain terminals
🛡️ Bulletproof Bedrock tool pairing
- Planner output is now injected as a
user-role context message rather than an orphanrole="tool"message — fixes Bedrock's "number of toolResult blocks exceeds number of toolUse blocks" error - Every
response.tool_callsentry gets a tool-result message unconditionally:- Success → real tool-result
- Retry → retries first, then final result or error
- Unknown tool → synthetic
"Error: tool X is not registered"tool-result
- Stable
call_{iteration}_{index}tool_call_ids round-trip through message metadata - Multi-iteration tool loops on Bedrock Claude, gpt-oss, and Anthropic native now work without
modify_paramsband-aids
🔑 Zero-friction provider switching
build_llm_from_env()walks upward from CWD to discover.env, so notebooks and scripts work regardless of where they're launched from- Seven providers:
openai,anthropic,bedrock,gemini,vertex,groq,together,ollama, plus a genericlitellmprovider - Per-provider credential validation with clear error messages
SHIPIT_OPENAI_TOOL_CHOICE=requiredenv var to force tool use on lazy models likegpt-4o-mini
🌐 In-process Playwright for open_url
OpenURLToolnow uses Playwright's sync Chromium directly (headless, realistic desktop Chrome UA, 1280×800 viewport)- Handles JS-rendered pages, anti-bot 503s, modern TLS/ALPN
- Stdlib
urllibfallback when Playwright is not installed — zero third-party HTTP dependencies in the core fallback path - Errors never raise out of the tool: they return as
ToolOutputwith awarningslist in metadata - Rich metadata:
fetch_method,status_code,final_url,title
🔍 Upgraded ToolSearchTool
- Replaced binary substring match with drk_cache-style fuzzy scoring:
SequenceMatcher.ratio() + 0.12 × token_hits - Configurable
limitparameter, clamped to[1, max_limit] - New init kwargs:
max_limit,default_limit,token_bonus - Structured error output for empty queries
- Ranked output with scores and "when to use" hints from
prompt_instructions - Noise filter: results below
score=0.05dropped
🪵 Full event taxonomy
14 distinct event types with documented payloads:
run_started, mcp_attached, planning_started, planning_completed, step_started, reasoning_started, reasoning_completed, tool_called, tool_completed, tool_retry, tool_failed, llm_retry, interactive_request, run_completed
🔁 Iteration-cap summarization fallback
- If the model is still calling tools when
max_iterationsis reached, the runtime gives it one more turn withtools=[]to force a natural-language summary run_completedis never empty for normal runs- Guarded with try/except so summarization failures can't mask the rest of the run
Other changes
pyproject.toml:[project.urls]now points to correct GitHub org, addsDocumentationandChangeloglinks.env.example: expanded with all new env vars documentednotebooks/04_agent_streaming_packets.ipynb: full rewrite with .env loading, credential visibility printer, and live Markdown updatesREADME.md: new v1.0 release section with 8 headline features- Full MkDocs Material documentation site at shipiit.github.io/shipit_agent
Breaking changes
None — this is the first stable release. Subsequent 1.x releases will maintain backward compatibility within the 1.x line.