← All releases

v2.17.0

October 14, 2026

Observability and prompt-governance release: every agent execution leaves a durable transcript you can read from the dashboard, role prompts become a versioned and overridable Markdown catalog, the clarity check names its assumptions and exclusions, work sources that cannot be read are no longer mistaken for quiet ones, and DevIntern stops stacking kernel sandboxes on itself.

Added

  • Durable harness run logs (DEV-128): every agent harness execution writes a self-describing transcript under ~/.devintern/logs/harness/ with a header (origin, task key, run id, harness, spawn label, working directory, command, start time), the interleaved stdout/stderr as it streamed, and a footer (end time, duration, exit code, signal, truncation, and any max-turns or usage-limit detection). Because persistence sits at the process boundary, a run that fails, times out, is killed, or exhausts its turn budget still leaves a usable log. This covers every execution — task implementation, plan retries, feasibility/clarity checks, estimation, git-hook fixes, auto-review, PR/MR review addressing, conflict resolution, and webhook review runs. The dashboard run-detail page surfaces a run’s transcripts, also available at GET /api/runs/:id/harness-logs and GET /api/runs/:id/harness-logs/:name. Logging is on by default (DEVINTERN_HARNESS_LOGS=0 disables it), a single transcript truncates at DEVINTERN_HARNESS_LOG_MAX_FILE_MB (default 10 MB), and the directory prunes at DEVINTERN_HARNESS_LOG_RETENTION_DAYS (30), DEVINTERN_HARNESS_LOG_MAX_FILES (500), and DEVINTERN_HARNESS_LOG_MAX_TOTAL_MB (256). Raw output is written unredacted so transcripts are complete; the dashboard masks obvious credentials (credential-looking KEY=value/KEY: value/"key": "value" assignments, well-known token shapes, and PEM private-key blocks) best-effort when serving — treat these logs as sensitive
  • Versioned prompt catalog (DEV-136): the role prompts DevIntern sends to the agent are now Markdown files with lightweight frontmatter (name, description, placeholders, requiredSections, {{placeholder}} substitution that fails loudly on a missing value) instead of inline TypeScript, so they can be reviewed, diffed, and overridden. The bundled catalog ships clarity.md, estimation.md, review.md, and fix.md. Override any prompt with a same-named file in .devintern-code/prompts/ (searched from your project root upward) or a DEVINTERN_PROMPTS_DIR directory; lookup order is explicit override, then DEVINTERN_PROMPTS_DIR, then .devintern-code/prompts/, then the bundled defaults. As a trust boundary, the auto-review loop pins review.md and fix.md to the bundled catalog (useAmbientOverrides: false) so a prompt committed on the PR branch can never rewrite the reviewer’s instructions or force an approval. Validate the catalog with bun run lint:prompts, which fails on malformed frontmatter, missing required sections, and undeclared/unused placeholders (also part of bun run lint and CI)
  • Clarity check surfaces assumptions and out-of-scope (DEV-138): the pre-implementation clarity assessment now reports the assumptions it made and the items it excluded from scope as explicit ## Assumptions and ## Out of Scope sections, included in the assessment written to the task directory, posted to Jira (Atlassian Document Format), and printed in the tracker comment for other trackers. Missing fields are tolerated and normalized to empty lists so older agent responses still parse
  • Unreadable work sources are reported, not swallowed (DEV-135): a work source (error monitor, issue poller, CI watcher) now distinguishes a read that returned nothing from a read that could not be performed instead of folding both into an empty success. A failed fetch yields unreadable (transient or malformed response), rate-limited (HTTP 429, with the Retry-After window recorded), or auth-failed (rejected token); the cursor is left unchanged on any of these so the next tick retries and no error is skipped because it was not fetched. The per-source status (including consecutive failures and the last successful read) is persisted in the workspace database beside the schedule state, and authentication failures are additionally logged as errors. The recorded status and retry window are not yet consumed to delay polling, and the dashboard does not yet surface them
  • DevIntern no longer nests kernel sandboxes (DEVINTERN-H): when DevIntern already runs inside a sandbox wrapper (for example a nono or srt shell, or a DevIntern agent that launched DevIntern), it detects the enclosing sandbox and does not add a second one, since nested kernel sandboxes fail before the agent starts — the agent inherits the existing confinement instead. This applies to auto and to explicitly requested providers that cannot nest (native, nono, srt), with a warning naming both; microVM providers (docker, smolvm) still run in their own guest and are not skipped. Detection reads each wrapper’s markers (NONO_CAP_FILE, SANDBOX_RUNTIME=1) from the real process environment captured before .devintern-code/.env is merged, so a repository cannot forge a marker to disable an explicitly requested sandbox, and an explicit provider is always validated for availability and harness compatibility first
  • Worker Pilot advertised in CLI help: the free interactive tier and the no-card Worker Pilot are now surfaced in devintern --help and devintern worker --help so the 14-day, no-task-limit trial is discoverable before a run instead of only in runtime license messages and docs

Fixed

  • Structured PR descriptions request a complete final briefing: implementation, plan retry, and verification repair prompts now request all six PR sections. Marked final summaries are published without streamed progress messages; raw output remains available for diagnostics, and agents that omit the markers retain the legacy fallback.

  • Corrupt CI retry state can no longer silently reset the retry cap: reading a malformed ci_fix_state row used to log and treat it as a fresh budget, which could reset the CI-fix attempt counter and let a failing PR be repaired forever. A malformed row now throws, the periodic watcher catches the error per PR and keeps polling the rest, and a fully green CI result is the one explicit path that repairs the row to a fresh budget. Recovery of pending/in-flight queue events likewise skips a single malformed row so healthy events still come back after a server restart, and attempts counters are validated as non-negative integers

Technical

  • SQLite rows are parsed at the storage boundary (DEV-157): a new state/row-parse.ts provides typed readers (required/optional string, number, enum, non-negative integer, and row-object parsing) so storage code stops casting raw query results with as; malformed rows surface as a typed RowParseError rather than propagating bad values
  • Task and delivery flows are bounded step sequences: both the task pipeline and the commit/review/publish delivery flow now run as named TaskStep sequences through a small step runner that can halt with a reason or repeat an earlier step under an explicit bound. Requirement verification before publishing (verify → repair → review, configurable maxIterations/minSeverity/onFail) is wired through this runner as internal groundwork