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 atGET /api/runs/:id/harness-logsandGET /api/runs/:id/harness-logs/:name. Logging is on by default (DEVINTERN_HARNESS_LOGS=0disables it), a single transcript truncates atDEVINTERN_HARNESS_LOG_MAX_FILE_MB(default 10 MB), and the directory prunes atDEVINTERN_HARNESS_LOG_RETENTION_DAYS(30),DEVINTERN_HARNESS_LOG_MAX_FILES(500), andDEVINTERN_HARNESS_LOG_MAX_TOTAL_MB(256). Raw output is written unredacted so transcripts are complete; the dashboard masks obvious credentials (credential-lookingKEY=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 shipsclarity.md,estimation.md,review.md, andfix.md. Override any prompt with a same-named file in.devintern-code/prompts/(searched from your project root upward) or aDEVINTERN_PROMPTS_DIRdirectory; lookup order is explicit override, thenDEVINTERN_PROMPTS_DIR, then.devintern-code/prompts/, then the bundled defaults. As a trust boundary, the auto-review loop pinsreview.mdandfix.mdto 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 withbun run lint:prompts, which fails on malformed frontmatter, missing required sections, and undeclared/unused placeholders (also part ofbun run lintand 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
## Assumptionsand## Out of Scopesections, 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 theRetry-Afterwindow recorded), orauth-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
nonoorsrtshell, 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 toautoand 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/.envis 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 --helpanddevintern worker --helpso 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_staterow 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, andattemptscounters are validated as non-negative integers
Technical
- SQLite rows are parsed at the storage boundary (DEV-157): a new
state/row-parse.tsprovides typed readers (required/optional string, number, enum, non-negative integer, and row-object parsing) so storage code stops casting raw query results withas; malformed rows surface as a typedRowParseErrorrather 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
TaskStepsequences 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, configurablemaxIterations/minSeverity/onFail) is wired through this runner as internal groundwork