Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions docs/code/dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ title: "Observability Dashboard"
description: "A local web dashboard for worker run history: per-task timelines, stage-by-stage outcomes, and aggregate stats"
section: "Server Automation"
order: 2
dateModified: 2026-07-03
dateModified: 2026-08-24
---

# Observability Dashboard

`devintern dashboard` serves a local web dashboard over the worker's run history: every task and PR mention the worker handled, the stages each run went through (feasibility, implementation, self-review, change requests, outcome), and aggregate stats like success rate and runs per week.
`devintern dashboard` serves a local web dashboard over the worker's run history: every task, PR mention, and scheduled automation the worker handled, the stages each run went through (feasibility, implementation, self-review, change requests, outcome), and aggregate stats like success rate and runs per week.

All data is read from the worker's local database (`.devintern-code/queue.db`). Nothing is uploaded anywhere: the dashboard runs on your machine and binds to localhost by default.

Expand All @@ -28,7 +28,7 @@ The standalone command reads the database in read-only mode, so it is safe to ru

## What it shows

- **Run list**: every run with its status, task key, origin (tracker task or PR mention), agent harness, PR link, and duration. Filter by status or origin.
- **Run list**: every run with its status, task key or automation id, origin (tracker task, PR mention, or scheduled), agent harness, PR link, and duration. Filter by status or origin (`origin=scheduled` isolates automation runs).
- **Run detail**: a stage-by-stage timeline for one run: the feasibility verdict, the implementation summary, each self-review iteration, each human change request and how it was handled, and the final outcome.
- **Stats**: runs per week, success and escalation rates, median run duration, and a per-harness breakdown over a selectable window (7, 30, or 90 days, or all time).
- **Worker status**: whether the daemon is running, queued and failed events, open agent PRs, and per-source poll cursors.
Expand All @@ -52,7 +52,7 @@ The dashboard is backed by a small read-only JSON API you can use directly, for

| Endpoint | Returns |
| --------------------------- | --------------------------------------------------------------------- |
| `GET /api/runs` | Paginated run list (`limit`, `offset`, `status`, `origin`, `taskKey`) |
| `GET /api/runs` | Paginated run list (`limit`, `offset`, `status`, `origin`, `taskKey`); `origin=scheduled` is supported |
| `GET /api/runs/:id` | One run with its stage timeline |
| `GET /api/stats?window=30d` | Aggregate stats (`7d`, `30d`, `90d`, or `all`) |
| `GET /api/worker` | Worker liveness, queue counts, agent PRs, poll cursors |
Expand Down
74 changes: 72 additions & 2 deletions docs/code/worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Worker Daemon"
description: "Run devintern as a single long-running worker that reacts to PR reviews and tracker changes"
section: "Server Automation"
order: 0
dateModified: 2026-08-17
dateModified: 2026-08-24
---

# Worker Daemon
Expand Down Expand Up @@ -34,6 +34,76 @@ devintern worker --query "status=todo" --listen

`devintern serve` still works as a deprecated alias for `devintern worker --listen`.

## Recurring automations

For a single repository, put recurring work in `.devintern-code/automations.toml`:

```toml
[[automations]]
id = "dependency-health"
enabled = true
interval = "6h"
prompt = """Pick one outdated dependency and upgrade it within the same major version.
Run the test suite; if anything breaks, revert the upgrade instead of fixing forward."""

[[automations]]
id = "flaky-test-triage"
enabled = true
cron = "0 9 * * 1"
prompt = """Re-run the test suite twice and look for flaky tests.
For each flaky test, add a short comment explaining the suspected race condition.
Do not change production code."""
```

Every entry needs a stable unique `id`, boolean `enabled`, non-empty `prompt`, and exactly one schedule. Intervals use positive minutes, hours, or days (`15m`, `6h`, `1d`). Cron expressions have five fields and use the worker host's timezone in v1; persisted occurrence times are UTC.

Configuration is validated as a group at worker startup and changes require a restart. An automation file is itself a valid event source, so `devintern worker` stays running without `--query` or `--listen` when at least one automation entry is configured (disabled entries are validated but not scheduled).

### What an automation is

Automations are independent of your task tracker: **the prompt is the task**. Each occurrence writes the prompt to a local markdown task file and feeds it through exactly the same pipeline as any other task — clarity check, planning, implementation, commit, PR creation, auto-review, run records. Nothing is created in your tracker, so no tracker credentials are needed for automation-only workers.

Concretely, each occurrence:

1. Writes `.devintern-code/automations/<id>/<timestamp>.md` (resolved like every other devintern state: the nearest `.devintern-code` walking up from the working directory).
2. Spawns the normal CLI on that file as a subprocess, so the run gets its own branch, commits, and — by default — a pull request.
3. Records the attempt with the `scheduled` origin and the automation id, so you can filter scheduled runs in the [dashboard](./dashboard.md).

Because the occurrence is just a markdown task, you can reproduce or rerun any occurrence by hand:

```bash
devintern .devintern-code/automations/dependency-health/2026-08-24T09-00-00-000Z.md
```

### Writing good prompts

The prompt replaces the ticket description the agent would normally read, so treat it like you would write a task for a new teammate:

- **Scope it to one change per run.** "Apply one safe improvement" produces reviewable PRs; "clean up the repository" produces sprawling ones.
- **State the guardrails.** What not to touch, when to stop, what must pass (`Run the test suite before committing`).
- **Say what done means.** The pipeline's incomplete-detection reads the agent output; concrete success criteria make escalations rare.
- Prefer recurring maintenance work (dependency bumps within a major, flaky-test triage, changelog refreshes, TODO sweeps) over open-ended feature work.

### Tuning how occurrences run

Occurrences use the same flag defaults as polled tasks: `WORKER_TASK_ARGS` overrides them (default `--create-pr`). For example, set `WORKER_TASK_ARGS=--auto-review` to have every automated PR go through the review loop too, or clear it to keep runs local without PRs. Note this variable applies to polled tracker tasks as well.

### Schedule semantics

Schedule cursors and claims live in `queue.db`. Missed occurrences coalesce to at most one immediate run after startup. The occurrence cursor advances atomically when claimed, so a crash does not replay a possibly completed run. Active claims receive heartbeats; after two minutes without a heartbeat a later due occurrence may recover the stale claim. If the same automation is still active at its next occurrence, that occurrence is logged and skipped without creating a run record. If the repository lock is held by another task, the occurrence is also skipped. This is an at-most-once policy: skipped occurrences are not replayed.

On shutdown the scheduler stops its timer, terminates active automation subprocess groups, waits for them to exit, and leaves their claims recoverable in SQLite.

### Troubleshooting

| Symptom | Likely cause |
| ---------------------------- | ------------------------------------------------------------ |
| No occurrences fire after editing the TOML | Config is loaded at startup — restart the worker. Startup validation errors name the offending entry. |
| `occurrence skipped: previous run is active` | The previous occurrence still runs (or its lease is stale). Long prompts may simply need a longer schedule. |
| `occurrence skipped: repository is busy` | Another task holds the repo run lock; the next occurrence will retry. |
| Scheduled runs missing from the dashboard | Filter the run list by origin `scheduled`; check the worker has an automation license (startup log). |
| Task files pile up under `.devintern-code/automations/` | They are small and safe to delete — they are only run inputs; the durable record is the run history in `queue.db`. |

## Polling mode

With `--query` (or `WORKER_TASK_QUERY`), the worker polls your tracker on an interval (default 60 seconds) and runs every task that matches the query. The query uses the same language as batch `--query` runs for your tracker, so "ready" means whatever your query says, for example a status or label.
Expand Down Expand Up @@ -113,7 +183,7 @@ Mention matching requires a resolvable bot identity, so this team/automation fea
- Events are persisted to a local SQLite queue (`.devintern-code/queue.db`) before processing, so a crash or restart never loses accepted work.
- Duplicate webhook deliveries are detected by GitHub's delivery id and skipped.
- Review feedback is processed before new task pickup: a human waiting on feedback beats a ticket that can wait a minute.
- One task runs at a time per repository.
- One task or scheduled automation runs at a time per repository.

## Instant events with the relay

Expand Down
Loading
Loading