{
  "markdown": "# dago\n\ndago is an idiomatic Go implementation of the Deep Agents SDK and the focused\nLangChain/LangGraph behavior it needs. It provides a provider-neutral tool loop,\nmiddleware, required delta channels, durable checkpoints, virtual filesystems,\ninline and background subagents, context compaction, skills, memory, and streaming without trying\nto reproduce either framework in full.\n\nThe public API is currently pre-1.0.\n\n[Try the shelley-in-dago browser demo](https://semistrict.github.io/dago/).\n\n## Install\n\n```sh\ngo get github.com/semistrict/dago\n```\n\ndago requires Go 1.26 or newer.\n\n### Interactive coding agent\n\n`dacode` is a terminal coding agent with durable threads and goals, streaming tool\nactivity, workspace-aware instructions and skills, and review gates for file writes\nand shell commands. It uses Bubble Tea, Bubbles, and Lip Gloss for its terminal\ninterface.\n\n```sh\ngo install github.com/semistrict/dago/cmd/dacode@latest\ndacode\n```\n\nRun the TUI directly without installing it:\n\n```sh\ngo run github.com/semistrict/dago/cmd/dacode@latest\n```\n\nFrom a dago source checkout, use `go run ./cmd/dacode` instead.\n\nOn first run, `dacode` opens OpenAI subscription sign-in and stores its refreshable\nsession under the user configuration directory. Set `OPENAI_API_KEY` to use API-key\nauthentication instead; an explicit key takes precedence over the saved session.\nInside the terminal, `/auth` (or `/connect`) opens the credential manager. API-key\ninput is masked and subscription sign-in can be cancelled without accepting a late\ncallback. Credential changes apply to newly built model runtimes; they never silently\nretarget an in-flight agent.\n\n`dacode config` lists canonical configuration keys, effective values, and sources.\nRemote execution is an explicit application capability. Builds that register provider\nfactories can use `--sandbox PROVIDER`, `--sandbox-id ID`,\n`--sandbox-snapshot-name NAME`, and a workspace-contained `--sandbox-setup FILE`.\nA bare `--sandbox` uses `sandboxes.default` only after that explicit flag; configuration\nalone never creates a remote resource. The stock binary lists the curated provider\ncontract but fails closed until an authenticated provider factory is linked.\nRun `dacode doctor` for bounded offline installation diagnostics, or\n`dacode doctor --json` for a stable machine-readable report. Credential values\nand provider URL paths, queries, user information, and fragments are omitted.\n`dacode install NAME` checks the build's closed optional-integration catalog.\nCurrent releases already ship every listed extra as Go package source, so the command\nreports the package or API to import and configure without changing the host. An\napplication must still import the integration and rebuild; the command does not add it\nto the running `dacode` binary. `--package` refuses every name because this build has\nno separately loadable package format and never downloads an arbitrary Go module.\n`dacode update CHANNEL ARTIFACT --manifest-base URL --public-key /absolute/key.pub`\nperforms a signed release check; add `--dry-run` to download and verify the artifact\nwithout writing, or `--apply` to replace the current executable. There is deliberately\nno built-in release URL or trust key yet: both must be supplied explicitly, manifests\nmust carry a valid Ed25519 signature, artifacts must match the signed SHA-256 and Go\nbuild identity, and development or locally replaced builds cannot be activated.\nSee [`docs/UPDATES.md`](docs/UPDATES.md) for the manifest contract and platform notes.\nFor interactive use, pass the same trust inputs as `--update-channel`,\n`--update-artifact`, `--update-manifest-base`, and `--update-public-key`; then bare\n`/update` opens the signed-update modal and `/auto-update` controls the persisted\npreference. `/notifications` configures dependency warnings, Ctrl+N opens pending\nactions, and `/trace` opens the active LangSmith thread only when a stored credential\nand an official trusted web endpoint are configured.\n`config get KEY`, `config path`, `config set KEY VALUE`, and `config unset KEY`\nprovide deterministic text or `--json` output and manage the owner-private versioned\nconfiguration file. Runtime precedence is default, config file, canonical environment\nvariable, `DEEPAGENTS_CODE_` override, `DEEPAGENTS_CLI_` override, then an explicit\ncommand-line flag. An explicitly empty prefixed string shadows the canonical value.\nCredentials are never printed or accepted by `config set`; keep them in the\nenvironment or existing sign-in store. Use `--config PATH` or `DACODE_CONFIG` to\nselect another file.\n\nNormal coding-agent launches also resolve environment files with shell exports first,\nthe nearest `.env` found from `--cwd` second, and `~/.deepagents/.env` last. Project\nfiles cannot replace process-launch, proxy, TLS, tracing-endpoint, MCP-trust, automatic\nreview, or terminal-identity controls; ignored key names are reported without their\nvalues. Files, lines, keys, values, ancestor search, and the final environment are\nbounded, and symbolic-link environment files are rejected.\n\nApplications can opt into owner-private structured debug traces with\n`DEEPAGENTS_CODE_DEBUG=1`. `DEEPAGENTS_CODE_DEBUG_FILE` selects an absolute file\ninside an owner-private directory, and `DEEPAGENTS_CODE_LOG_LEVEL` accepts\n`DEBUG`, `INFO`, `WARNING`, or `ERROR`. Trace files are bounded and common\ncredential attributes are redacted, but messages can still contain sensitive\napplication data and should be reviewed before sharing.\n\nOn macOS, model-driven shell commands first run under the native process sandbox.\nIt permits workspace and temporary-directory writes, denies network access, and\nreports policy violations as a structured approval boundary. Auto mode reviews only\ncommands that cross that boundary; workspace-contained commands continue without a\nreview call. The `execute` tool describes this policy and accepts\n`sandbox_permissions: \"require_escalated\"` with a concise `justification` when the\nmodel knows a command needs to run outside it; that request is reviewed before the\ncommand runs. The checkout containing the starting directory is writable, including\nits validated Git administration directories, so commits and other Git operations work\nfrom linked worktrees. Workspace-confined file mutations proceed without reviewer\nlatency in Auto mode, while direct file access to protected metadata remains denied;\nexternal tool gates still use direct approval rules.\nThe read-only reviewer defaults to `gpt-5.6-luna`, falls back to the active model only\nwhen that implicit default cannot be resolved, and can be overridden with\n`--approval-model`. `--manual-review` requires a user decision for every gated action,\nand `--yolo` bypasses review and the local process boundary. The first\nsuccessful Auto-mode\nenable shows a versioned safety notice: Enter keeps Auto and records the notice in the\nprivate local state directory, while Esc returns to Manual without recording it. The\nfirst YOLO entry is gated more strictly: YOLO remains inactive until Enter successfully\npersists the current warning policy; `m` selects Manual and Esc keeps the prior mode.\nThe active approval mode is also stored per durable thread under a SHA-256-derived\nkey. Resuming a thread restores its own mode, and live Shift+Tab or slash-command\nchanges are persisted before they take effect. Missing, invalid, or unreadable thread\nrecords use Manual. The server consults the same record for gated actions in both the\nmain agent and delegated subagents, so UI state alone cannot enable unrestricted work.\nAt a Manual approval prompt, the warning-bordered menu shows numbered Approve,\nthread-Auto, and Reject choices for one call or a batch. Arrow keys or `j`/`k` move\nthe cursor, Enter selects, `1`/`2`/`3` select by position, `y` approves, `a` enables\nAuto (or returns an Auto fallback to Manual), `n` or Esc rejects, and Tab opens a\nsingle-line rejection-reason field. Long shell commands can be expanded with `e`;\nwrite, edit, delete, and other tools receive bounded purpose-specific previews, while\nrecognized credential-file contents are hidden from both the prompt and tool row.\nEnter submits a rejection reason (or a bare rejection when blank), while Esc or `n`\nfirst closes the field without deciding. If a gated\naction arrives within two seconds of composer input, the decision keys stay attached\nto the draft until typing becomes idle; the approval is revealed after at most 30\nseconds even if typing continues. The same deferral applies when Auto review falls\nback to a user decision.\n\n`/auto model` selects the current session's classifier, Ctrl+S persists the default,\nand `/auto model clear` returns to the main model. Auto assesses the complete pending\ntool-call batch through a required structured decision tool and requires exact\ntool-call ID coverage.\nMalformed or unavailable reviews deny conservatively before bounded consecutive,\ntotal-denial, or configuration-fault thresholds return control to the user. A distinct\nclassifier receives only bounded, redacted trusted-user context and summarized action\nmetadata, never assistant text or raw tool results.\n\nUse `-n 'task'` for one-shot operation, pipe a task to standard input, or pass\n`--stdin` to require piped input explicitly. `--quiet` prints only the final\nresponse, `--no-stream` buffers it, and `--json` emits one versioned result object.\nFor unattended work, `--max-turns N` and `--timeout SECONDS` bound execution and\nexit with status 124 when the bound is reached; the default turn bound is 50.\n`--recursion-limit N` separately bounds graph steps within each turn and defaults\nto 2000.\nUse `-m 'task'` to submit an initial interactive prompt, or `-s NAME` to invoke a\nproject skill around the initial interactive or one-shot request. Runtime skill\nprecedence, from lowest to highest, is built-ins, enabled plugin skills, the selected agent profile,\n`~/.agents/skills`, project `.deepagents/skills`, project `.agents/skills`,\n`~/.claude/skills`, and project `.claude/skills`. `--startup-cmd CMD` runs a local setup\ncommand in the workspace before skill discovery and before the first model turn.\nIts literal, bounded output stays local rather than entering model context;\nnon-zero exits warn and continue, while cancellation stops startup.\nUse `dacode skills list|info|create|delete` to manage user or `--project` skills,\nand `dacode skills trust list|add|revoke|clear` to manage exact external-symlink\ntargets. In the TUI, `/skills` lists the effective catalog, `/skill:NAME [task]`\ninvokes one skill, and `/remember` and `/skill-creator` invoke the standard authoring\nskills. An untrusted external symlink opens an exact-target approval prompt; declining\ndoes not read its instructions. The built-in `deepagents-thread-inspector` uses the\nread-only `dacode skills inspect-thread` JSON workflow for bounded local summaries,\ntranscripts, and latest-turn inspection.\nUse `dacode plugin list|install|uninstall|enable|disable` and\n`dacode plugin marketplace list|add|remove` to manage the owner-private plugin store.\n`plugins` is an alias for the same non-interactive command. In the TUI, `/plugins`\nopens the Discover, Installed, and Marketplaces views; keyboard actions install,\nenable, disable, uninstall, add, or remove entries and then offer a reload. `/reload`\natomically refreshes reloadable environment/configuration values and rebuilds plugin\nskills, hooks, MCP connections, and web credentials without discarding the current\nruntime if rebuilding fails. Installed plugins are enabled by default and take effect\non the next process, ACP session, or successful reload: skills are\nqualified as `plugin@marketplace:skill`, MCP server names are scoped to the plugin,\nand declared lifecycle hooks execute as trusted host commands. Plugin installation\ntherefore grants instruction, process, and network authority; inspect the publisher\nand pinned revision before enabling one.\nUse `-r ID` to resume a durable thread and `--cwd PATH` to select the workspace.\nRun `dacode resume` to choose a session before opening the TUI, or\n`dacode resume ID` to resume a known session. Inside the TUI, `/threads` opens\nthe same picker. Selected sessions restore their transcripts and approval mode before continuing.\nBefore any transcript is loaded, a session owned by another agent or original\nworking directory requires an explicit switch/stay decision. Threads above the\nconfigured context threshold also offer an exact-checkpoint compaction choice.\n`/offload` (alias `/compact`) runs that same bounded compactor directly and\ncommits its state only after summary generation succeeds.\n\nThe first interactive launch offers a keyboard-driven setup flow and stores its\ncompletion marker and selected preferences in the private state directory.\n`/restart` is available when the process owns an explicitly configured local\ndevelopment server; it opens a confirmation modal and reports restart failures\nwithout exposing the child process or its environment.\n`/agents` opens the named-agent picker. Put an agent's instructions in\n`<state-dir>/<name>/AGENTS.md`; each agent loads and updates only that durable memory,\nand switching starts a new thread. Arrow keys or Tab move through the picker, Enter\nswitches, Ctrl+S\ntoggles the startup default, and Esc cancels. The built-in `dacode` agent remains\navailable and creates an empty memory file on first use. `-a NAME` selects or creates\na profile directly; without it, startup uses `agents.default`, then a valid\n`agents.recent`, then the built-in profile. Each profile also has private `skills/`\nand `sessions/` namespaces, and session browsing is restricted to the selected agent.\nUse `dacode agents list` to inspect profiles and\n`dacode agents reset --agent NAME [--target SOURCE] [--dry-run]` to restore the\nbuilt-in prompt or copy another profile's prompt. Reset replaces the destination\nprofile, including its skills and session namespace; preview it before use when that\nstate matters. Pass\n`--memory-auto-save=false`, or set `DEEPAGENTS_CODE_MEMORY_AUTO_SAVE=false`, to load\nmemory in reference-only mode without asking the model to persist new learnings.\n`/docs`, `/changelog`, and `/feedback` open the project documentation, releases,\nand issue form in the active browser environment.\nUse `/editor` or Ctrl+X to edit the current draft with `$VISUAL`, then `$EDITOR`,\nor the platform's default text editor. Saving a blank draft cancels the edit.\nUse `/effort` to choose one of the active model profile's reasoning levels,\n`/effort LEVEL` to set one directly, or `/effort clear` to restore the provider\ndefault. The selected level is saved per model and shown beside the model name.\nUse `/theme` to preview and select the full built-in color catalog. Arrow keys or\nTab preview, Enter saves the global choice, Esc restores the prior theme, `n`\ntoggles labels and canonical keys, and `t` saves the highlighted theme for the\ncurrent `TERM_PROGRAM`. Terminal mappings override the global choice, while\n`DEEPAGENTS_CODE_THEME` overrides both. Custom `[themes.NAME]` tables in\n`~/.deepagents/config.toml` require a label, may set `dark`, and may override any\nsemantic color with `#RRGGBB`; `ansi-dark` and `ansi-light` preserve the terminal\npalette instead of imposing a background.\nThe composer completes slash commands and `@` workspace paths, turns valid dropped\nimages and videos into bounded structured attachments, persists non-command history,\ncollapses large pastes until submission, and accepts messages while a turn is running\nby queueing them. Prefix a draft with `!` to run it in the local shell and\ninclude its bounded output as context for the next request; `!!` runs it locally\nwithout adding the command or output to model context. Shift/Alt/Ctrl+Enter inserts a\nnewline. Draft action buttons clear or copy the current input.\n\nOn macOS, local file tools are confined to the workspace and expose it as virtual `/`.\nShell commands start in the real working directory; the native policy permits host\nreads but confines writes to the active checkout, its validated Git metadata, and\ntemporary directories until an exact boundary crossing is approved. Other local\nplatforms currently retain unrestricted host paths. Remote sandbox sessions use the\nprovider's working directory and cannot access local host paths.\n\nThe transcript renders streamed Markdown, lifecycle-styled tool rows, grouped tool\nsummaries, skill invocations, and bounded inline write/edit diffs. Ctrl+O expands or\ncollapses the latest eligible message, tool row, skill, or tool group. `/line-numbers`\ntoggles gutters for newly created diffs and persists the preference; PageUp hydrates\nolder rows when a long restored transcript is using its sliding render window.\n\nWhen the agent needs information it cannot infer, it can pause the active turn with\none or more text or multiple-choice questions. Enter confirms an answer, Tab and\nShift+Tab move between questions, every choice list includes a free-form Other entry,\nand Esc dismisses the prompt. Required answers cannot be blank. Ctrl+X edits the\nfocused free-form answer in the configured external editor. Completed question rows\nshow only `User answered` or `Question failed`; answer text remains in the durable\nmodel transcript but is excluded from automatic-review audit input.\n\n`--shell-allow-list recommended` makes approved read-only commands execute inline\nwhile rejecting every other shell request instead of pausing for review. Pass a\ncomma-separated list such as `recommended,git,gh` to add trusted executables.\n`--shell-allow-list all` explicitly removes shell-command checks; use it only in an\nisolated environment.\nOne-shot runs expose no shell tool unless a shell allow-list is supplied.\n\nMCP servers are discovered from `~/.deepagents/.mcp.json`, then the project's\n`.deepagents/.mcp.json`, then project-root `.mcp.json`; later same-name definitions\nwin. `--mcp-config PATH` selects one explicit file instead. User and explicit servers\nconnect at startup. Project servers require a definition-bound remembered approval,\nan operator-controlled process allow-list, or the explicit per-run\n`--trust-project-mcp` flag. Unapproved or disabled project entries do not connect.\nConfigured tool names use `SERVER_TOOL`, support allow/deny patterns, and retain MCP\nread-only annotations for headless approval policy. OAuth-declared servers remain\ndisconnected until the separate login flow supplies credentials:\n\n```sh\ndacode mcp login <server>\n```\n\nThe command accepts `--mcp-config PATH` for one explicitly trusted file; otherwise it\nuses the same definition-bound project trust gate and precedence as startup. Slack\nuses its workspace-aware public-client flow, GitHub Copilot MCP uses its device flow,\nand other HTTPS endpoints use MCP dynamic registration with PKCE. Authorization can\nopen the platform browser or use `--no-browser`; paste-back input remains bounded.\nTokens are stored outside MCP configuration under\n`~/.deepagents/.state/mcp-tokens/` with private permissions and are reused only by the\nsame server name and exact endpoint on a later startup. The login does not mutate a\ncurrently running tool registry.\n\nWithin the terminal, `/mcp` opens the current server/tool viewer. Enter expands tools,\nstarts login, or shows a bounded error; F2 stages a server enable/disable change for\nthis session. `/mcp login NAME` starts the same endpoint-bound OAuth policies and\n`/mcp reconnect` rebuilds the idle runtime. Login and enablement changes remain pending\nuntil reconnect succeeds; Esc defers them without discarding the pending state.\n\nUse `/goal <objective>` for work that should continue across turns until complete or\nblocked. The agent drafts observable acceptance criteria first; accept, edit, reject\nwith feedback, or cancel that proposal in the review panel. Accepted criteria remain\nvisible with the durable goal and are evaluated before a requested completion is\ncommitted. `/goal show`, `/goal amend <feedback>`, `/goal pause`, `/goal resume`,\n`/goal clear`, and `/goal budget <tokens|clear>` control the persisted goal.\n`/goal model` and `/goal max-iterations` are aliases for its rubric grader settings.\nActive goals resume automatically when the thread becomes idle. Pass `--goal TEXT`\nto open the same review flow at interactive startup.\n\nUse `/workflows` to open the live workflow control panel. It shows background run\nstatus, current phase, agent progress, and errors; use the arrow keys to select a run\nand `c` to cancel it. `/workflow <saved-name-or-script-path>` launches a saved\nworkflow directly. Names resolve from `.claude/workflows` and `.agents/workflows` in\nthe workspace, while explicit paths are restricted to the workspace and application\nstate directories.\n\nUse `/rubric set <criteria>` for a persistent quality gate, `/rubric next <criteria>`\nfor one turn, or `/rubric file <path>` to load a UTF-8 criteria file. `/criteria` is\nan alias. `/rubric show`, `/rubric clear`, `/rubric model`, and\n`/rubric max-iterations` inspect and tune grading. For one-shot execution, combine\n`-n TASK` with `--rubric 'criteria'` or `--rubric @path`; optional\n`--rubric-model` and `--rubric-max-iterations` select the grader behavior.\n\nUse `dacode acp` (or `--acp`) to serve the coding agent to an ACP-compatible editor\nover standard input and output. The editor owns the session and permission prompts\nin this mode; `--yolo` remains available to bypass mutating-tool approval gates.\nEach editor session gets its own workspace runner and any declared stdio, HTTP, or\nSSE MCP servers. HTTP headers are forwarded for per-session MCP authentication.\n\n`--serve-xtermjs` serves the same PTY-backed TUI on a loopback-only web address\nand prints its URL. Use `--xtermjs-address HOST:PORT` to select a specific\nloopback listener.\n\nFor an explicitly managed local development companion, pass an absolute\nexecutable with `--local-dev-server PATH`. Repeat `--local-dev-arg VALUE` for\nliteral arguments and select its loopback readiness origin/path with\n`--local-dev-endpoint` and `--local-dev-health-path`. The child receives only a\ntyped, non-credential configuration payload and a small platform environment;\nadditional non-secret names require an explicit `--local-dev-inherit-env NAME`.\nThe process tree is stopped when either interactive or one-shot execution exits.\nThis opt-in supervisor is unavailable in ACP server mode.\n\nUse the repository-root GitHub Action for bounded CI tasks, durable cache-backed\nagent memory, and optional skills-repository installation. See [`ACTION.md`](ACTION.md)\nfor its inputs, secure defaults, and a pinned workflow example.\n\n### Managed-agent project scaffold\n\n`dago init [name]` creates the pinned managed-agent starter layout: `agent.json`,\n`AGENTS.md`, an empty `tools.json`, `.gitignore`, an example skill, and a researcher\nsubagent. When the name is omitted, the command prompts for it. Existing directories\nare left untouched unless `--force` is explicit; force refreshes only the starter\nfiles and preserves unrelated content.\n\nBare `dago` no longer starts an interactive chat. Run `dacode` for the interactive\ncoding agent; `dago` is reserved for explicit project and managed-service commands.\n\n```sh\ndago init my-agent\ncd my-agent\n```\n\nManaged workspaces can also list, inspect, and explicitly delete remote agents.\nAuthentication resolves `LANGSMITH_API_KEY` before `LANGCHAIN_API_KEY`; the endpoint\nresolves the corresponding `LANGSMITH_ENDPOINT` / `LANGCHAIN_ENDPOINT` variables\nand otherwise uses the hosted API. Only HTTPS origins are accepted.\n\n```sh\ndago agents list\ndago agents get --include-files AGENT_ID\ndago agents delete AGENT_ID\n```\n\nDeletion prompts unless `--yes` is supplied.\n\nDeploy the current scaffold with `dago deploy`. The first run creates a remote\nagent; later runs patch metadata and synchronize only the managed `AGENTS.md`,\n`tools.json`, `skills/`, and `subagents/` directory projection. The remote ID is\npinned outside the checkout under `~/.deepagents/deployments/`, keyed by the\nproject’s absolute path and authenticated endpoint.\n\nCreation uses a stable server idempotency key and recovery marker derived from the\nauthenticated endpoint and required project-owned `extras.dago_deployment_id`.\n`dago init` generates that identifier and preserves it during forced scaffold\nrefreshes. To make `--reset` create a genuinely new remote agent, rotate the identifier\nin `agent.json` first; this keeps the new logical creation explicit and portable.\n\n```sh\ndago deploy --dir ./my-agent --dry-run\ndago deploy --dir ./my-agent\n```\n\n`--detach` skips the health request, `--reset` forgets cached state and creates a\nnew agent, and `--yes` acknowledges an `agent_id` explicitly declared by\n`agent.json`. A declared remote must already carry this project's deployment\nidentity; the client will not race to adopt an unbound agent. Dry runs require no\ncredential and perform no state or network I/O.\n\nThe same authenticated workspace can manage its MCP server registry. Identifiers\naccept an exact ID, unique name, or normalized URL. Static headers are supplied\nexplicitly and redacted from inspection output; OAuth records can be registered\nwithout storing a token in the project.\n\n```sh\ndago mcp-servers list\ndago mcp-servers add --name tools --header X-Api-Key=VALUE https://tools.example\ndago mcp-servers add --auth-type oauth --connect --no-browser https://oauth-tools.example\ndago mcp-servers get tools\ndago mcp-servers update tools --url https://new-tools.example\ndago mcp-servers connect --no-browser tools\ndago mcp-servers tools tools\ndago mcp-servers delete tools\n```\n\nTool discovery prints a paste-ready `tools.json` snippet. OAuth connection registers\nthe workspace provider, prints its HTTPS verification URL, optionally opens the\nplatform browser, and performs bounded long polling; use repeated `--scope`,\n`--force-new`, `--timeout`, or `--no-browser` as needed. Deletion prompts unless\n`--yes` is explicit.\n\n## Use dago as a library\n\nModels implement the small `damodel.Chat` interface, and tools implement\n`datool.Tool`. This complete example uses the OpenAI adapter and a typed local tool;\nthe agent and tool APIs remain provider-neutral:\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/semistrict/dago\"\n\t\"github.com/semistrict/dago/dagent\"\n\t\"github.com/semistrict/dago/daproviders/openai\"\n\t\"github.com/semistrict/dago/datool\"\n)\n\ntype addInput struct {\n\tA int `json:\"a\" description:\"First number\"`\n\tB int `json:\"b\" description:\"Second number\"`\n}\n\nfunc main() {\n\tchat := openai.NewAPIKey(os.Getenv(\"OPENAI_API_KEY\"), \"gpt-5\", openai.Options{\n\t\tContextWindow: 128_000,\n\t})\n\tadd := datool.New(\"add\", \"Add two integers.\", func(_ context.Context, input addInput) (int, error) {\n\t\treturn input.A + input.B, nil\n\t})\n\n\tagent := dago.New(chat,\n\t\tdago.WithSystemPrompt(\"Use tools when they help answer accurately.\"),\n\t\tdago.WithTools(add),\n\t)\n\tresult, err := agent.Invoke(context.Background(), dagent.Prompt(\"What is 17 plus 25?\"))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tfmt.Println(result)\n}\n```\n\nFilesystem tools are opt-in through `dago.WithFilesystem`. With the default state\nbackend, files live in the agent’s `files` delta channel, are isolated by thread,\nand become durable when a checkpoint saver is configured. Pass an explicit store,\ncomposite, local-shell, or remote sandbox backend when the agent should operate\nelsewhere.\n\nAgent-owned facilities use that same backend automatically. Configure them as values\ninstead of constructing middleware with a duplicate backend argument:\n\n```go\ncompiled := dago.New(chat,\n\tdago.WithBackend(workspace),\n\tdago.WithSkills(dago.Skills{Sources: []string{\"/skills\"}}),\n\tdago.WithMemory(dago.Memory{Sources: []string{\"/AGENTS.md\"}}),\n)\n```\n\nMemory sources use the backend's virtual paths. Machine-managed onboarding blocks\ninside those files are protected automatically, including for subagents that share\nthe filesystem. Set `Memory.ReadOnly` to use the built-in reference-only prompt while\nstill loading the configured files.\n\nDurable goals are an opt-in agent facility and require a checkpoint saver. The\nmiddleware exposes `create_goal`, `get_goal`, `get_rubric`, and constrained\n`update_goal` tools; `dagoal.Service` provides host-owned pause, resume, budget,\nobjective, criteria, and clear operations. When accepted criteria must gate goal\ncompletion, place `dagoal.RubricCompletionMiddleware` before `dago.Rubric` so a\nmodel-requested completion is committed only after a satisfied verdict:\n\n```go\ngoalOptions := dagoal.Options{}\ncompiled := dago.New(chat,\n\tdago.WithMiddleware(\n\t\tdagoal.Middleware(goalOptions),\n\t\tdagoal.RubricCompletionMiddleware(dago.RubricStatusKey, string(dago.RubricSatisfied)),\n\t\tdago.Rubric(chat, dago.RubricOptions{}),\n\t),\n\tdago.WithSaver(saver),\n)\ngoals := dagoal.NewService(compiled, goalOptions)\n```\n\nBinary media is returned opaquely by default. Supplying\n`dago.WithFilesystem` can configure a `VideoExtractor`, which changes video\n`read_file` pagination to seconds and returns sampled JPEG frames. `davideo.NewFFmpeg` is the optional\nready-made implementation; the FFmpeg executable remains an external deployment\ndependency.\n\nDeclarative subagents use the same functional options as top-level agents. A nil\nmodel inherits the parent model, and tools inherit unless `WithTools` overrides them:\n\n```go\nresearcher := dago.NewSubagent(\n\t\"researcher\",\n\t\"Researches a topic and returns a concise answer.\",\n\tnil,\n\tdago.WithSystemPrompt(\"Research the delegated topic.\"),\n\tdago.WithTodo(),\n)\ncompiled := dago.New(chat, dago.WithSubagents(researcher))\n```\n\nThey always receive tool-call repair and inherit parent facilities that were\nexplicitly enabled for declarative children, including filesystem, interpreter,\nmemory, summarization, approval, and prompt caching. Precompiled graphs can be registered with `NewRunnableSubagent`; only\ndelegation options such as `WithInheritedState` apply because their construction is\nalready complete. Human approval, including approval inside a subagent, requires a\ncheckpoint saver so the exact pending tool call can resume without replaying completed\nsibling tools.\n\n`dacode` also discovers declarative subagents from `NAME/AGENTS.md` directories.\nProject definitions under `.deepagents/agents` override same-name definitions in the\nselected agent profile's `agents` directory. Frontmatter requires `description`, may\nset `name` and `model`, and the remaining Markdown is the subagent system prompt. An\nomitted or empty model inherits the main model. Defining `general-purpose` replaces\nthe built-in general agent; otherwise the built-in remains available.\n\n### Workflows\n\nWorkflows are an optional extension that lets a model launch a deterministic\nJavaScript orchestration script in the background. The host supplies a\n`daworkflow.AgentRunner`, which is the policy boundary for models, reasoning\neffort, custom agent types, structured output, and worktree isolation. The manager\nowns cancellation and same-session replay and should be closed with its application\nscope:\n\n```go\nmanager := daworkflow.NewManager(runner, daworkflow.Options{\n\tSessionDirectory: sessionDir,\n})\ndefer manager.Close()\n\ncompiled := dago.New(chat,\n\tdago.WithMiddleware(daworkflow.Middleware(manager)),\n)\n```\n\nThe `workflow` tool accepts an inline `script`, a resolver-backed saved `name` or\n`script_path`, or a completed `resume_from_run_id`, and immediately returns task and\nrun IDs. Scripts begin with a runtime-evaluated `export const meta = {...}` declaration\nand can use `agent`, `parallel`, `pipeline`, `phase`, `log`, `args`, `budget`, and one\nlevel of nested `workflow` calls. The runtime has no filesystem or Node APIs and\nrejects implicit clocks and randomness. Concurrency, agent count, collection size,\nmemory, execution time, and tokens are bounded through `daworkflow.Options`. When\n`SessionDirectory` is set, the manager persists the script, per-agent transcripts,\nreplay journal, and final JSON result under that directory. `Options.Completed` can\nbridge terminal runs into the host application's native task-notification channel.\n\nThe terminal host implements `isolation: \"worktree\"` for local Git workspaces. Each\nisolated agent call starts from the configured workspace's committed `HEAD` on a new\n`workflow/agent-*` branch. A clean checkout is removed after the call; an unchanged\nbranch is removed, a committed branch is retained, and a checkout with uncommitted\nchanges is retained and reported as an agent failure with its recovery path. Worktree\nisolation is a coordination boundary rather than a security sandbox, and it is not\navailable when the terminal host is using a remote or custom backend.\n\n### Type-safe tools\n\n`datool.New` derives an object schema from the handler's input struct, validates\nmodel arguments, and decodes them before calling the handler:\n\n```go\ntype weatherInput struct {\n\tLocation string `json:\"location\" description:\"City and state\" jsonschema:\"minLength=1\"`\n\tUnits    string `json:\"units,omitempty\" jsonschema:\"enum=celsius|fahrenheit,default=celsius\"`\n}\n\nweather, err := datool.New(\"weather\", \"Get the current weather.\", func(ctx context.Context, input weatherInput) (string, error) {\n\treturn input.Location + \": sunny\", nil\n})\n```\n\nFields use `encoding/json` names and `omitempty` behavior. A `description` tag\nsets field documentation; `jsonschema` supports requirements, formats, enums,\ndefaults, examples, string/array/object lengths, patterns, and numeric bounds.\nHandlers that need call state can use `datool.RuntimeFromContext(ctx)`.\nReturning a `datool.Result` preserves its full content, artifact, state update,\ninterrupt, and handoff; strings become text results and other values become JSON text.\nRuntime schema details can be layered onto the generated schema with functional\noptions such as `WithPropertyType`, `WithPropertyEnum`, `WithPropertyValue`,\n`WithPropertySchema`, `WithoutProperty`, or the lower-level `WithTransformSchema`.\n\n### Web tools\n\nThe opt-in `daweb` package provides `http_request` and HTML-to-Markdown `fetch_url`\ntools. Supplying a Tavily key also enables `web_search`; a blank key leaves that tool\nout of the returned set:\n\n```go\nwebClient := daweb.NewClient(daweb.Options{})\ntools := daweb.Tools(webClient, os.Getenv(\"TAVILY_API_KEY\"))\ncompiled := dago.New(chat, dago.WithTools(tools...))\n```\n\nThe client accepts only HTTP and HTTPS URLs, rejects credentials and non-public\naddress ranges, pins each connection to its validated DNS answers, revalidates every\nredirect, ignores environment proxies, and bounds request, response, rendered page,\nredirect, and timeout resources. Library applications opt in explicitly. The coding\nagent includes `fetch_url` by default and prefers a model provider's hosted web-search\ntool, including OpenAI and Anthropic integrations. OpenAI search is enabled by default;\n`--model-params '{\"web_search\":false}'` disables it. When the resolved model does not\nprovide web search, `dacode auth set tavily` or `TAVILY_API_KEY` supplies an\napproval-gated local fallback. Stored service credentials take precedence over\nenvironment values. If both are configured, provider-hosted search wins and the local\n`web_search` tool is not exposed.\n\nTyped adapters keep the state and checkpoint wire formats flexible without\nrequiring application assertions. Use `dagent.Field` with a\n`dagent.FieldSpec[T]` to declare typed reducers, `datool.StateAs[T]` for tool\nstate, and `dagent.DepsAs[T]` or `datool.DepsAs[T]` for application dependencies\nsupplied through `WithDependencies`. `dagent.ResumeAs[T]` accepts both live Go values\nand checkpoint-restored plain JSON values. Structured results can be declared\nwith `dagent.StructuredOutputFor[T]` and decoded with\n`dagent.StructuredAs[T]`; the latter validates against the schema derived from T.\n`damessage.MetadataAs[T]` and `damessage.SetMetadata` provide the same typed\nboundary for raw JSON metadata maps.\n\n`dagent.RuntimeModel` consumes the `model` configurable value, resolves it through\na required caller-owned `ModelResolver`, swaps only that invocation's model, and\npersists the selected spec in private thread state unless `Ephemeral` is requested.\nThe resolver retains ownership of provider clients, credentials, caching, and any\nnetwork access; the middleware bounds the model spec and contains resolver panics.\n\nExternal local event ingress is opt-in through `daeventbus`. Supply the sink and\nan absolute Unix socket path positionally, then run the source under an owning\ncontext:\n\n```go\nsource := daeventbus.NewUnixSource(sink, socketPath, daeventbus.Options{})\nerr := source.Run(ctx)\n```\n\nEach newline-delimited JSON object carries `kind` (`command`, `prompt`, or\n`signal`), `payload`, and optional `bypass` and `correlation_id` fields. The\nsource replies once per line with an ACK or bounded NACK. It only validates and\nforwards events: the application-owned sink decides what any command, prompt,\nsignal, or bypass hint means. Unix ingress reports an explicit unsupported error\non Windows rather than silently opening another transport.\n\nOwned agent streams support `for event, err := range stream.Events()`. Model\nstreams support `for chunk, err := range stream.Chunks()`. Both iterators close\ntheir stream on completion, error, or early loop exit; `Next` and `Close` remain\navailable for explicit control.\nApplicable built-in Anthropic harness profiles resolve from the model's provider and\nidentifier. The full Nemotron 3 Ultra repair, retry, progress-budget, tool-selection,\nentity-resolution, and answer-completeness stack is available explicitly from\n`daproviders/nemotron`. Provider construction defaults for OpenAI, NVIDIA, and\nOpenRouter are available as an explicit `daproviders/profile.Profiles` value.\n`daproviders/profile.Resolver` composes those profiles with caller-owned provider\nfactories to resolve `provider:model` strings without hiding credential or optional\ndependency ownership. Model-spec matching normalizes known provider aliases, and\nBedrock detection covers provider-prefixed and Amazon Nova identifiers.\n\nFull provider selection is available from `daproviders/modelconfig`. It combines the\npinned provider catalog, stored/environment credential precedence, paired base URLs,\nmodel parameters, profile overrides, retries, and owner-private default/recent\npreferences while keeping provider factories explicit. See [model\nconfiguration](docs/MODELS.md). `dacode` exposes `--model-params`,\n`--profile-override`, `--max-retries`, `--default-model`, and\n`--clear-default-model`; selecting an integration not compiled into the application\nfails explicitly without network or package discovery.\n\n`--model claude_agent:sonnet` selects the compiled Claude CLI provider. It uses\nprint-mode bidirectional stream JSON, disables local customization and every built-in\ntool except `Skill`, and exposes only the current agent request's tools through an\nephemeral authenticated loopback MCP server. Effective skills are materialized in a\ntemporary session plugin, and an MCP tool description larger than Claude's inline\nlimit becomes a generated skill with a short loading instruction. The outer dago\nagent executes MCP tools and returns their results while the same CLI process remains\nalive; partial text and reasoning events stream through `dacode` as they arrive.\nNative JSONL reconstruction and `--resume` are used only after a process restart. See [model\nconfiguration](docs/MODELS.md#coding-agent-flags) for the isolation boundary and\nsupported parameters.\n\n`--model anthropic:MODEL` selects the direct Messages API provider. Hosted web search\nis enabled by default, and `hosted_tools`, `mcp_servers`, `betas`, plus forward-compatible\ntop-level Messages parameters can be supplied with `--model-params`.\n\nLocal Ollama model discovery is explicit and credential-free. Supply the HTTP\ntransport and endpoint positionally, then call `Discover` when a local model picker\nor configuration flow needs a refresh:\n\n```go\ndiscovery := ollama.NewDiscovery(http.DefaultTransport, \"\", ollama.DiscoveryOptions{})\nmodels, err := discovery.Discover(ctx)\n```\n\nAn empty endpoint uses `http://127.0.0.1:11434`. Discovery accepts only literal\nloopback HTTP(S) origins (the exact `localhost` name is rewritten to a literal),\nperforms one bounded `/api/tags` request, sorts and deduplicates names, and never\nadds authentication. It is not invoked automatically by the agent or provider\nresolver.\n\nLangSmith LLM Gateway routing is similarly explicit and provider-neutral. Supply\na caller-owned model factory and gateway key positionally; an empty endpoint uses\nthe managed gateway:\n\n```go\ngateway := langsmithgateway.NewResolver(factory, \"\", gatewayKey, langsmithgateway.Options{})\nmodel, err := gateway.ResolveModel(ctx, \"openai:gpt-4.1\")\n```\n\nThe factory receives the routed endpoint, key, and original model specification\nand remains responsible for provider SDK construction and network policy. The\nbuilt-in pinned routes cover Anthropic, Baseten, Fireworks, Google GenAI, and\nOpenAI. Construction and endpoint inspection perform no I/O.\n\n## JavaScript interpreter\n\nEnable a persistent, sandboxed QuickJS-ng REPL with `Interpreter`. The `js_eval`\ntool supports top-level await, console output, functions and variables that persist\nthrough checkpoints, and concurrent programmatic tool calls. It runs the exact\n`quickjs-rs` 0.2.5 WASM guest under Wazero's interpreter backend, including in Go\nbrowser-WASM builds. TinyGo builds exclude the Wazero-backed implementation;\nenabling `Interpreter` in a TinyGo build fails during agent construction, and the\nShelley TinyGo application omits `js_eval` from its tool catalog.\n\n```go\ncompiled := dago.New(chat,\n\tdago.WithSaver(saver),\n\tdago.WithInterpreter(dago.Interpreter{\n\t\tPTC:             []string{\"read_file\", \"glob\", \"grep\", \"search\"},\n\t\tPTCTransparency: true,\n\t}),\n)\n```\n\nThe first memory image is checkpointed as an anchor. The generated QuickJS guest\nuses WAFL-style 4 KiB write barriers, so subsequent checkpoints copy only dirty\nmemory pages. A nil `PTC` allowlist exposes only `read_file`, `glob`, and\n`grep`; an empty non-nil list disables PTC. Explicitly allowlisted tools execute\ninside `js_eval` and do not pass through model-tool approval middleware, so mutating\ntools should only be included when that direct authority is intended.\n`PTCTransparency` defaults to false. When enabled, each `tools.*` invocation emits\nthe ordinary streamed tool lifecycle with its arguments, output, status, and parent\n`js_eval` call ID. User interfaces and protocol adapters can therefore render PTC\ncalls like model-originated tool calls without adding them to model-visible history.\n\n## OpenAI adapter\n\nThe focused Responses API adapter supports text and multimodal messages, tool calls,\nparallel tool calls, JSON Schema structured output, token streaming, usage, prompt\ncaching metadata, API keys, and an explicit subscription OAuth session. Standard\nOpenAI endpoints use persistent Responses WebSocket connections by default and send\nincremental input on compatible successive turns. Set `ResponsesWebSocket` to\n`new(false)` to force HTTP; compatible custom endpoints can opt in with\n`new(true)`. Standard endpoints also enable remote server-side compaction by default:\nat 90% of `ContextWindow` (or 200,000 tokens when it is unknown), the adapter sends a\ncompaction-trigger Responses request, preserves its encrypted state, and resumes the\nturn. Set `ServerCompaction` to `new(false)` to disable it or set\n`CompactionThreshold` to override the trigger point.\n\n```go\nchat := openai.NewAPIKey(os.Getenv(\"OPENAI_API_KEY\"), \"gpt-5\", openai.Options{\n\tContextWindow: 128_000,\n})\n```\n\nThe core package never discovers credentials or chooses a provider. OAuth token\npersistence is opt-in and writes only to the caller-provided private file.\n\n## OpenRouter adapter\n\nThe OpenRouter adapter uses OpenRouter's Responses API and preserves the same\ntext, multimodal, tool-calling, structured-output, reasoning, web-search, usage,\nand streaming contracts as the OpenAI adapter. It also supports optional app\nattribution and provider routing:\n\n```go\nchat := openrouter.New(os.Getenv(\"OPENROUTER_API_KEY\"), \"anthropic/claude-sonnet-4.6\", openrouter.Options{\n\tAppURL:   \"https://example.com/my-agent\",\n\tAppTitle: \"My Agent\",\n\tRouting: &openrouter.ProviderRouting{\n\t\tIgnore:         []string{\"azure\"},\n\t\tDataCollection: \"deny\",\n\t},\n\tContextWindow: 200_000,\n})\n```\n\n`BaseURL` defaults to `https://openrouter.ai/api/v1`. Credentials remain\nexplicit; the adapter does not read environment variables itself.\n\n## Durable execution\n\n```go\nsaver, err := sqlite.Open(\"agent-checkpoints.sqlite\")\nif err != nil {\n\tlog.Fatal(err)\n}\ndefer saver.Close()\n\ncompiled := dago.New(chat, dago.WithSaver(saver))\nresult, err := compiled.Invoke(ctx,\n\tdagent.FromCheckpoint(dacheckpoint.Config{ThreadID: \"conversation-1\"}),\n\tdagent.Prompt(\"Inspect the project.\"),\n)\n```\n\nAgents expose checkpoint history, replay, thread fork, and thread deletion. SQLite\nand PostgreSQL savers match the supported Python table layouts and delta-snapshot rules.\nCross-language payload compatibility is intentionally limited to the safe plain-data\nsubset in [`docs/SERIALIZATION.md`](docs/SERIALIZATION.md); Python-specific object\nrecords are rejected with typed context instead of reconstructed.\n\n## Long-running agent host\n\n`datalon` is an experimental, provider-neutral host for local assistants that stay\nrunning across channel messages and scheduled jobs. It owns one runtime, any number\nof channel adapters, and an optional scheduler; starts and stops them in dependency\norder; serializes work per channel conversation; and lets `/stop` cancel the active\nturn and discard turns already queued behind it. Different conversations can still\nmake progress concurrently.\n\nThe zero-value configuration uses the current working directory, a 500-step\nrecursion limit, finite message/send/shutdown bounds, and private assistant state at\n`~/.deepagents/default/`. Set a stable assistant ID to isolate another state tree.\nPassing a nil runtime deliberately selects the echo runtime, which makes channel and\nscheduler integration testable before a model-backed runtime is configured.\n\nChannel tool approval is an experimental convenience for a trusted operator, not a\nproduction authorization boundary. `datalon/approval.FromEnvironment` parses the\ncomma-separated `DEEPAGENTS_TALON_INTERRUPT_ON_TOOLS` overlay with finite limits;\nlisted local or MCP tool names are exact and always override a same-name disabled\nbase rule. Apply the resulting rules to the main agent and inherited subagents, then\nresolve every `human_approval` interrupt through the invocation's channel handler:\n\n```go\npolicy, err := approval.FromEnvironment(nil, approval.Options{})\nif err != nil {\n\treturn err\n}\nrules := policy.ApprovalRules(applicationRules...)\nagent := dago.New(chat, dago.WithApprovalRules(rules...))\n\n// In the runtime's bounded invoke/resume loop:\nresume, err := approval.ResolveInterrupt(ctx, request, result.Interrupts[0])\n```\n\n`WithApprovalRules` carries the combined rules into dago's built-in general-purpose\nand declarative subagents. A separately compiled or remote subagent is a separate\nexecution boundary and must receive the same policy itself. Handlerless scheduled\nruns, timeouts, cancellation, transport errors, malformed requests, invalid replies,\nand unsupported decisions all fail closed. Only a recognized reply from the exact\norigin channel conversation and initiating sender resolves one pending approval;\nspoofed, stale, duplicate, or ordinary messages remain on the serialized agent path.\n\nFleet exports can be materialized into an explicit assistant state directory before\nstarting the host:\n\n```sh\ngo run ./cmd/datalon import-fleet <fleet-export.zip> <assistant-state-dir>\n```\n\nThe importer writes `AGENTS.md`, `skills/`, and remapped `agents/<name>/AGENTS.md`\nprompts. Fleet `tools.json` files are import input only, and `config.json` is ignored.\nRequested remote tools produce a credential-free OAuth `.mcp.json` plus a\nhuman-readable `.mcp.json.setup` handoff. The completion summary recommends a\n`DEEPAGENTS_TALON_INTERRUPT_ON_TOOLS` value when the export marked tools for approval.\nRepeated imports refresh only these importer-managed paths and preserve unrelated\nassistant runtime state.\n\n`datalon/mcp` loads the resulting MCP configuration without reading credentials\nfrom it. Resolution checks `DEEPAGENTS_TALON_MCP_CONFIG`, then `MCP_CONFIG`, then\n`~/.deepagents/.mcp.json`. HTTP, SSE, and trusted local stdio servers are supported,\nincluding allow/deny tool patterns and per-server load status. Applications supply\ntheir HTTP policy and may connect the discovered tools to any model-backed runtime:\n\n```go\noauth := mcp.NewOAuthFactory(httpClient, tokenStore, interaction)\nloader := mcp.NewClient(httpClient, oauth, mcp.Options{})\ntools, configPath, err := loader.LoadDiscovered(ctx, nil, \"\")\ndefer tools.Close()\n```\n\nApplications that need the pinned provider policies can instead use\n`oauthpolicy.NewFactory`: Slack uses its public client with PKCE, state validation,\nand optional workspace selection; GitHub Copilot MCP uses its public device flow;\nall other HTTPS servers retain standards-based metadata discovery and dynamic client\nregistration. The required HTTP client, token store, and UI-agnostic interaction are\nstill supplied by the application.\n\nOAuth tokens stay in a caller-selected private token store. The command-line flow\nuses `~/.deepagents/.state/mcp-oauth/` and paste-back authorization, so it does not\nneed to open a browser or own a listener:\n\n```sh\ngo run ./cmd/datalon mcp config\ngo run ./cmd/datalon mcp login <server>\n```\n\n`datalon/cron` adds a versioned `cron/jobs.json` store, a minute-granularity\npersistent scheduler, and conversation-scoped `create_job`, `list_jobs`, `edit_job`,\nand `remove_job` tools. One-shot and recurring jobs are claimed on disk before they\nrun, so a restart cannot repeat the same interval. Each run persists its last status\nor bounded error and emits `talon_event` JSON lifecycle records; results beginning\nwith `[SILENT]` deliberately skip delivery.\n\n`datalon/lifecycle` applies bounded retention to sensitive assistant state.\nIts zero options preserve completed cron records for 30 days, remove inbound\nmedia after 24 hours, and enforce the pinned 1 GiB global artifact ceiling.\nState root and cron store are required positionally; construction performs no\nI/O. Operators can preview the same plan without deletion:\n\n```go\nretention := lifecycle.New(config.StateDir(), cronStore, lifecycle.Options{})\npreview, err := retention.DryRun(ctx)\nreport, err := retention.Clean(ctx)\n```\n\nReports expose only counts and hashed audit references, never prompts, paths,\nfilenames, content, or job IDs. The entire finite walk is validated before file\ndeletion, linked and special state fails closed, cron replacement remains atomic,\nand cleanup secures managed state owner-only. Durable channel sessions and remote\ntraces are preserved unless the caller explicitly opts a confined local artifact\ndirectory into retention; session deletion additionally requires a static risk\nacknowledgement. See [`datalon/lifecycle`](datalon/lifecycle/README.md).\n\nPer-run LangSmith tracing is opt-in through `datalon/tracing`. The provider-neutral\nwrapper preserves the runtime result even when tracing fails, bounds copied inputs,\noutputs, errors, and metadata, and records channel or scheduler metadata on one root\nrun per invocation. The environment helper follows the Talon opt-in contract:\n`LANGSMITH_TRACING` must be truthy and `LANGSMITH_API_KEY` must be non-empty.\n\nLong-running applications can use `tracing.NewManager` for the broader coding-agent\npolicy. A required credential store is resolved once against a caller-supplied\nenvironment snapshot; a stored key enables tracing unless a recognized flag opts\nout, agent traces receive their own project, the original tracing variables can be\nrestored for shell subprocesses, and orphaned tracing fails closed. Region aliases,\nbounded replica projects, and replica ingestion endpoints are supported without\nmutating process-global environment. `Configuration.ResolveSink` passes credentials\nonly to a required caller-owned provider factory, and `tracing.NewManaged` redacts\nknown credential values while emitting the primary and replica spans.\n\n```go\nlangsmithClient := langsmith.NewClient()\ndefer langsmithClient.Close()\nruntime = tracing.NewFromEnv(\n\truntime,\n\tlangsmithtrace.New(langsmithClient),\n\tconfig.AssistantID,\n\tnil,\n\ttracing.Options{},\n)\n```\n\nThe zero options use project `deepagents-talon`, run name `talon.agent`, and finite\npayload and completion bounds. The application owns endpoint policy, credentials,\nclient shutdown, and flushing.\n\n`tracing.NewURLResolver` separately resolves a project web URL through a required\ncaller lookup, caches only validated HTTPS results with finite timeout/TTL/count\nbounds, and builds credential-free thread links. It never opens a browser; terminal\nor headless presentation remains an application concern.\n\nInbound voice transcription is opt-in through `datalon/speech`. Wrap any channel\nthat supplies a confined local `voice_path` or `media_path`; voice and video messages\nreceive the transcript while ordinary files pass through unchanged. `NewLocal`\ndefaults to `nvidia/parakeet-tdt-0.6b-v3` on CPU, converts a private bounded copy to\n16 kHz mono WAV with ffmpeg, and invokes the optional local Transformers pipeline\nthrough `python3`. Set the device to `cuda` for compatible local hardware. For a\nnon-Parakeet model, `NewOpenAI` requires the caller's HTTP client, API key, and model\npositionally and uses the bounded audio-transcription endpoint. The environment\nparser also accepts legacy `SPEECH_ENABLED` and `SPEECH_DEVICE` values.\n\nTelegram is an additive Bot API channel. Its token and HTTP client are required\npositional dependencies; construction performs no network work. Long polling is the\ndefault, uses finite request/retry/payload limits, and can persist its update offset:\n\n```go\ntelegramChannel := telegram.New(\n\tos.Getenv(\"TELEGRAM_BOT_TOKEN\"),\n\thttp.DefaultClient,\n\ttelegram.Options{\n\t\tExposure: telegram.AllowlistExposure(\n\t\t\t[]string{\"123456789\"},\n\t\t\t[]string{\"-1001234567890\"},\n\t\t),\n\t},\n)\nhost := datalon.NewHost(runtime, config, telegramChannel)\n```\n\nPrivate messages are selected by user ID, channel posts by chat ID, and group or\nsupergroup traffic is ignored. `telegram.SelfExposure` requires operator IDs;\n`telegram.OpenExposure` requires the exported risk acknowledgement. The alternate\n`telegram.NewWebhook` constructor requires its webhook secret positionally and returns\nan `http.Handler`, while the application continues to own TLS, routing, listener\nlifecycle, source-address policy, and webhook registration.\n\nWhatsApp is an additive channel backed by the packaged Node bridge. The bridge\nbinds only to loopback, requires bearer authentication, persists pairing state\nin an owner-private directory, and reports `qr_pending` while its operator QR is\nshown on standard output. The application supplies an authenticated transport\nand stable session directory positionally and owns the Node process lifecycle:\n\n```go\nwhatsappTransport := whatsapp.NewHTTPTransport(\n\t\"http://127.0.0.1:3000\",\n\tos.Getenv(\"WHATSAPP_BRIDGE_TOKEN\"),\n\twhatsapp.HTTPOptions{},\n)\nwhatsappChannel := whatsapp.New(\n\twhatsappTransport,\n\t\"/private/operator/whatsapp-session\",\n\twhatsapp.Options{},\n)\n```\n\nSelf-only exposure is the default; allowlists accept exact conversations or\ncase-sensitive mention patterns, and open exposure requires an explicit risk\nacknowledgement. Outbound chunks carry a bot header. Media is hard-capped at\n64 MiB and staged only from a caller-confined outbound root. See\n[`datalon/whatsapp`](datalon/whatsapp/README.md) for bridge setup and security\nboundaries.\n\n## Agent Client Protocol\n\n`daacp` exposes an agent to ACP-compatible editors over newline-delimited JSON-RPC.\nThe process must reserve standard output for protocol messages; send logs to standard\nerror.\n\n```go\nserver := daacp.New(compiled, daacp.Options{\n\tName:    \"workspace-agent\",\n\tVersion: \"1.0.0\",\n})\nif err := server.Serve(ctx, os.Stdin, os.Stdout); err != nil {\n\tlog.Fatal(err)\n}\n```\n\nThe adapter supports ACP v1 session creation and durable loading with replay-marked\nhuman, assistant, and tool history. A load is accepted only when its absolute working\ndirectory matches the directory stored with the original session. Factory-backed\nservers created with `daacp.NewFactory` can advertise model choices: changing the\n`model` Session Config Option rebuilds that session's runner with the selected model\nin `daacp.AgentSessionContext` while retaining its checkpointed conversation. With\ndurable loading enabled, the replacement runner also persists the selection through\n`daacp.SessionConfigSaver`, and `session/load` restores it before replaying history.\nOnly advertised model identifiers reach the factory. `dacode acp` advertises the\nstartup model first, followed by its supported OpenAI model choices.\n\nThe adapter also supports\nprompts, cancellation, close, authentication handshakes, session\nconfiguration negotiation, streamed text and reasoning, tool status and progress,\nplans, and approve/reject permission requests. A session factory can construct an\nisolated runner from the requested working directory and MCP declarations; stdio,\nHTTP, and SSE MCP transports are supported by `dacode`. The session working\ndirectory is also available to tools as `daacp.ConfigurableCWD`. Additional roots,\nclient filesystem/terminal delegation, and ACP-routed MCP transport are not\nadvertised.\n\n## LangSmith Studio\n\n`dago dev` exposes configured Go agent factories through the LangGraph Agent\nServer protocol, persists development threads and store values in SQLite, watches\nGo/module/config/environment files, and rebuilds the server when they change.\n\n```sh\ngo install github.com/semistrict/dago/cmd/dago@latest\n```\n\nExport a factory that accepts the server-owned runtime. Using its saver and store\nis required for Studio state, history, replay, and thread operations to address the\nsame durable data as agent runs:\n\n```go\nfunc NewAgent(_ context.Context, runtime daserver.Runtime) (*dagent.Agent, error) {\n\treturn dago.New(chat,\n\t\tdago.WithSaver(runtime.Saver),\n\t\tdago.WithStore(runtime.Store),\n\t\tdago.WithDependencies(runtime.Deps),\n\t), nil\n}\n```\n\nPoint `dago.json` at the package and exported factory:\n\n```json\n{\n  \"graphs\": {\n    \"agent\": {\n      \"path\": \"./agent:NewAgent\",\n      \"description\": \"Workspace agent\"\n    }\n  },\n  \"env\": \".env\"\n}\n```\n\nThen start the API and Studio:\n\n```sh\ndago dev\n```\n\nThe default API is `http://localhost:2024`; `--no-browser`, `--host`, `--port`,\n`--config`, and `--n-jobs-per-worker` are available. Development data and the\ngenerated wrapper stay under the ignored `.dago_api` directory. The\n[`examples/studio`](examples/studio) configuration is a network-free smoke test:\n\n```sh\ndago dev -c examples/studio/dago.json\n```\n\nThis is a focused local Studio integration, not a claim that arbitrary LangGraph\napplications can run in Go. Its supported Agent Server resources and current\nlimits are listed in [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md).\n\n## Packages\n\n| Package | Purpose |\n|---|---|\n| `dago` | Deep Agent constructor plus filesystem, JavaScript interpreter, subagent, summary, skill, memory, profile, and rubric middleware |\n| `dagent` | Provider-neutral model/tool graph, middleware lifecycle, approval, retry, todo, streaming, and checkpoint operations |\n| `dagoal` | Durable goal state, model tools, host lifecycle controls, accounting, and continuation messages |\n| `dacost` | Bounded streaming token accounting, provider/model/purpose reports, and local pricing catalogs |\n| `damessage`, `damodel`, `datool`, `dastate` | Stable public contracts and reducers |\n| `damodel/modeltest` | Scripted and prompt-driven predictable model doubles for offline tests and examples |\n| `dabackend` | State, memory, host fi",
  "bytes": 60000,
  "sha": "14a135e2009e6d3c77efe95bea36b7f8ef12ef501f0669420cdd6d3e65df890b",
  "repo_slug": "semistrict/dago",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_semistrict_dago_openwiki_index_md_3a27b560/readme"
}