Changelog
Source:NEWS.md
codeagent (development version)
Concurrent sub-agents (opt-in via
settings$async_subagents, default OFF): theAgenttool can run asynchronously so multiple sub-agent delegations requested in a single turn execute concurrently (via ellmer’stool_mode = "concurrent") on the async streaming paths (CLI REPL / Shiny app). Sync one-shotcodeagent()transparently falls back to sequential sub-agents, since async (promise-returning) tools are invalid underChat$chat(). Also adopts ellmer 0.4.2 (set_model(),chat_posit()).Background sub-agents (opt-in via
settings$background_agents, default OFF; requiresmirai): a newBackgroundAgenttool delegates a task to a fire-and-forget sub-agent running in amiraidaemon and returns immediately (non-blocking). Its result is polled and surfaced back to the model on a later turn via the system reminder, mirroring Claude Code’s async agents. Users can also spawn and inspect background agents directly with the/bg <task>and/bgstatusslash commands (REPL and Shiny).
codeagent 0.1.0
First public release. codeagent is an R-native reimplementation of a command-line coding agent, built on ellmer and btw. It provides the agent harness (loop, tools, permissions, compaction, hooks, skills) plus a CLI REPL and a shiny user interface.
Model tier env var rename — breaking changes
Three environment variables have been renamed to remove vendor-specific names. Update your .Renviron / settings.json env block accordingly:
| Old | New | Meaning |
|---|---|---|
CODEAGENT_DEFAULT_SONNET_MODEL |
CODEAGENT_MODEL |
Everyday main model |
CODEAGENT_DEFAULT_OPUS_MODEL |
CODEAGENT_HEAVY_MODEL |
High-capability model |
CODEAGENT_SMALL_FAST_MODEL |
CODEAGENT_FAST_MODEL |
Cheap/fast model |
Tier aliases used in /model and codeagent.md also changed: "sonnet" → "main", "opus" → "heavy", "haiku" → "fast".
CODEAGENT_MODEL now serves dual purpose: it sets both the default model and the "main" tier alias (previously CODEAGENT_MODEL and CODEAGENT_DEFAULT_SONNET_MODEL were separate; they are now merged).
CLI/ink unified entry point — breaking changes (plan #20)
Default permission mode is now
"default"across all entry points (CLI, Shiny, ink). Previously all CLI subcommands defaulted to"bypass". Write operations (file edits, shell commands) now prompt for approval unless you explicitly opt into bypass mode.-
-y/--yolo— new global flag for the CLI that enables bypass mode (skips all permission prompts). Equivalent to Claude Code’s--dangerously-skip-permissions. Short-hand:-y.codeagent -y # bypass REPL codeagent app -y # bypass Shiny app codeagent run "q" -y # bypass one-shot query codeagentwithout a subcommand now starts the interactive REPL directly (equivalent tocodeagent chat). Previously a subcommand was required.-p/--print-mode— new flag for one-shot non-interactive output.codeagent "query"orcodeagent -p "query"runs a single query and exits.-mnow means--model(breaking). The old-m/--modealias has been removed. Use-y/--yolofor bypass mode instead.-
ink_ui()gainsyolo = FALSEparameter. WhenTRUE, setsINK_YOLO=1so the codeagent backend runs in bypass mode. Theinkaiterminal command also accepts-y/--yolo.ink_ui("codeagent", yolo = TRUE) # bypass # or from terminal: inkai codeagent -y # bypass INK_YOLOenv var — set to"1"to enable bypass mode in ink when launching theinkaicommand directly:INK_YOLO=1 inkai codeagent.codeagent_app(permission_mode = "default")unchanged — Shiny was already correct; passpermission_mode = "bypass"explicitly when needed.R/cli_dispatch.R— new internal helpers.ca_resolve_mode()and.ca_dispatch()expose CLI dispatch logic as testable pure functions.
Unified agent streaming API (plan #19)
codeagent_stream_async()— new exported function. Streams one agent turn asynchronously (coro::asyncpromise). Runs the full turn pipeline (compaction, system-reminder injection, session save, cost tracking viaget_cost(include="last")). Fires typed callbacks:on_delta,on_thinking,on_tool_request(pre-gate, from stream chunk),on_tool_result(with typeddisplaycontract from.adapt_tool_result()),on_error,on_usage. Supportsstream_controllerfor cancellation andtool_modefor concurrent tool execution.codeagent_stream()— synchronous wrapper aroundcodeagent_stream_async()usinglater::run_now()to pump the event loop. Handles Ctrl+C gracefully (cancels the stream viastream_controller, does not re-throw the interrupt condition). Intended for CLI and ink frontends.Turn pipeline helpers (
R/turn_pipeline.R, internal):.turn_setup()consolidates compaction + resource replacement + system-reminder injection into one call..turn_teardown()consolidates session save + usage +cost_last. Both are now shared by console, Shiny, and ink.Shiny system-reminder injection fixed.
server_chat.R’sstream_tasknow injects the<system-reminder>block (date/iteration/cwd/memory) on every turn, matching the behaviour of the console REPL andagent_loop().Console Ctrl+C repair.
codeagent_console()now creates astream_controllerper turn and catchesinterruptconditions, cancelling the stream gracefully. Previously Ctrl+C could corrupt the chat state.Callback deduplication.
.register_repl_tool_callbacks()is now guarded by.chat_once()to prevent stacking display callbacks ifcodeagent_console()is called more than once on the same chat object..patch_interrupted_chat()retired. Removed from all call sites. ellmer 0.4.0+ (#840) and 0.4.1+ (#643) handle orphaned tool requests andAssistantPartialTurnautomatically.inkAssistantUItool cards upgraded.ink_reply_stream()now callscodeagent_stream()when available (full turn pipeline + display contract).on_tool_resultreceives a richdisplayfield (title/kind/payload) instead of a plain string. Theink_server()initialises per-sessionCompactionController/ContentReplacementState/session_idso turns are properly managed.
Multi-agent teams (post-0.1.0 additions)
-
Task DAG.
team_coordinate()gainsblocked_by— task dependencies given by 1-based index. A task is only claimed once all its blockers aredone, so workers respect ordering while still parallelising independent tasks. Cyclic graphs are rejected up front. The shared board’s claim is now dependency-aware and atomic (BEGIN IMMEDIATE). -
Worktree isolation + crash recovery.
worktree = TRUEruns each worker in its own git worktree;board_reclaim_stale()(wired into the worker loop) resets a crashed worker’s timed-out task back to pending so its dependents are never blocked forever. -
Event-driven board.
board_watch()(built on thewatcherpackage) reacts to board changes without polling, powering an event-driven coordinator / live board view (falls back to polling when watcher is unavailable). -
LLM-lead coordinator.
team_lead(goal, max_rounds =)faithfully ports Claude Code’s COORDINATOR_MODE: a lead model decomposes the goal into a task DAG, the work-stealing team runs it, then the lead reviews results and either finishes or adds a follow-up round (bounded loop; decompose/review/coordinate steps are injectable for testing). -
Live dashboard.
team_dashboard(db_path)is a standalone Shiny app that monitors a running team’s board in real time — task table (coloured by status), a progress bar, and the inter-agent message log.
Shiny app UX (post-0.1.0 additions)
Instant startup. The UI shell now renders immediately; the slower tool + skill registration runs in the background behind a prominent “Initializing codeagent…” overlay, with the chat input gated until it completes. Pass a bare
ellmer::Chattocodeagent_app()for this lazy path.Skill metadata disk cache.
list_skills_meta()now caches parsed skill metadata on disk (<config>/cache/skills/, keyed by cwd + aSKILL.mdmtime/count signature), so the slash typeahead and skill tool are near-instant on every launch after the first (a disk hit skips the ~20s directory scan). The cache self-invalidates when anySKILL.mdchanges or a skill is added/removed.Single-file viewer. Clicking a file in the Files tree now opens it in one static, scrollable “File” tab (code / Markdown / image / CSV) with a filename header and close button, replacing the old per-file tabs that could overflow and cover the tab strip.
Security & testing improvements (post-0.1.0 additions)
keyring integration (
R/keyring.R): Optional API key storage via the OS credential store (keyringpackage).setup.Roffers the keyring as an alternative to~/.Renvironwhen the backend is available. Includes.keyring_available()(session-cached probe),.keyring_store_key()with graceful fallback to~/.Renviron, and.keyring_get_key(). On headless/server environments the keyring backend probe returnsFALSEand all functions degrade silently to the existing~/.Renvironpath.webfakes agent integration tests (
tests/testthat/test-webfakes-agent.R): 12 tests that mock the LLM API endpoint withwebfakes, exercising the full agent loop — tool dispatch (Read, Write, Bash), permission gate (bypass vs plan), error recovery (HTTP 500), and skill invocation — without hitting a real LLM.Explicit tool names:
bash_tool(),read_tool(),write_tool(),edit_tool(),multi_edit_tool(),glob_tool(),grep_tool(),ls_tool()now passname=toellmer::tool()so the model can refer to tools by their canonical names (Bash, Read, Write, Edit, MultiEdit, Glob, Grep, LS).
Agent harness
- Agentic loop (
agent_loop()) with max-turns, token budget, verification, and error recovery (prompt-too-long, rate-limit, network, and auth handling). - Seven-mode permission system:
default,plan,accept_edits,bypass,dont_ask,auto, andbubble(sub-agent decisions bubble to the parent). Fine-grained rules match on tool arguments (e.g.Bash(npm run test *)). - Twelve-event hook system covering tool, permission, message, and lifecycle events, configurable declaratively from
settings.json. - Five-level context compaction (snip, session memory, full summary, prompt fallback, context collapse).
- System prompt with tone, task, convention, tool-use, and R-specific guidance.
Tools
- Core tools:
Bash,Read,Write,Edit,MultiEdit,Glob,Grep,LS. -
RunRexecutes R code behind the permission gate; with sandboxing enabled it runs in an isolatedcallrsubprocess with a scrubbed environment (secrets hidden), no.Renvironreload, and a wall-clock timeout. -
btwtool groups (docs, git, pkg, env, etc.), web fetch and search, notebook tools, task and persistent-todo tools. - Optional codebase retrieval via
ragnar(vector + keyword search).
Coordination
- Sub-agents via
agent_tool(), with optional git-worktree isolation and persistent “sidechain” sessions. - Parallel teams:
team_run()(fixed fan-out) andteam_coordinate()(work-stealing over a shared SQLite board with inter-agent messaging), both capped to the container’s CPU quota viaparallelly. - Plan-mode tools let the model enter and exit read-only planning mid-turn.
State and configuration
- Sessions saved as JSONL with lossless tool-call preservation; fork, rename, tag, resume, and rewind (
truncate_chat_turns()//rewind). - Auto-memory persisted across sessions, with relevance selection by a small fast model.
-
settings.jsonconfiguration mirroring command-line agents:envblock, model tiers, permissions, hooks, MCP servers, sandbox, effort level, and more. - Model switching mid-conversation (
switch_model()), lossless where possible.
Interfaces
- CLI:
codeagentexecutable withrun,chat/repl,app,skills,mcp, andinfosub-commands; the REPL streams output, shows tool activity, and renders reasoning blocks. -
shinyapp (codeagent_app()) with tool cards, session management, and theme options. - MCP server (
codeagent_mcp_server(), stdio and HTTP) and MCP client (register_mcp_client(), stdio) for external tool interoperability.