Skip to content

Plan, run, report ​

awaywork plan shows what a run would do, awaywork run does it, and awaywork report reads back what it did.

Preview the next run ​

awaywork plan shows each source and provider as it loads (Getting started), then becomes a view to browse:

☾ >_ awaywork  You're away, your agents work

Providers
  present run (outside the windows): present_session_max
  provider  window     used  ceiling  set by  resets in  session / stop at
  claude    seven_day  5%    25.7%    pacing  5 runs     2% / 40%
    other limits: reserve cap 90%

▾ Needs you 1
  ▾ tracker T 1
    T-4  Export invoices as CSV  add repo

▾ Units 3
       item  rule  skill              provider  deliver   title
  ▾ acme/api 2
    1  #1    #1    fix (built-in)     claude    draft_pr  Add rate limits to the public API
       + api#5: same feature, matched #3
    3  #2    #2    review (built-in)  claude    report    Cache user sessions
  ▾ acme/web 1
    2  #3    #1    fix (built-in)     claude    draft_pr  WIP: new billing page

▾ Skipped 2: 1 no_rule, 1 over_cap
  ▾ tracker T 1
    T-7  Onboarding emails  no rule
         closest #3 implement: type is task, wants issue
  ▸ acme/api 1

⏎ unfold  o open  s skip  a approve  ? help  q quit
  • Units name the item (api#1 is acme/api#1; a tracker key stays as is), the rule it matched, the skill, provider and delivery.
  • Needs you is the skipped items only you can unblock, each ending on what to do: add repo for a task with no repo.
  • Skipped is the config doing its job, counted by kind.
  • ⏎ pages why an item is planned or skipped, o opens it, s skips it in the coming runs, ? lists the rest (key table).

Piped or in CI it prints the same as text, the skipped items only counted, and ends on the commands that dig in:

awaywork plan --skipped [kind]  lists them
awaywork plan --why <key>       says why an item is planned or not

plan --skipped lists the skipped items with their reason, Needs you first; plan --skipped no_rule lists one kind. plan --why <key> explains one item, with the queue when it matched no rule:

$ awaywork plan --why T-7
tracker T-7  Onboarding emails
  https://tracker.acme.dev/T-7
  skipped: no_rule
    matched no rule; closest #3 implement: type is task, wants issue

Queue
  #1  fix        type=pr mine=true
  #2  review     type=pr review_requested=true
  #3  implement  type=issue
  #4  fix        column=QA

A planned item shows its unit, rule, skill, provider and branch instead. With no queue in your config, plan says Nothing will run: the config has no queue; /away or awaywork init writes one.

awaywork plan --rules shows what each rule takes now, without probing quota:

Queue
  #1  fix     source=github type=pr mine=true checks=failing
       1 taken: acme/api#1
  #2  fix     source=github type=pr mine=true unresolved_threads!=0
       0 taken
  [...]
  #4  review  source=github type=pr review_requested=true trusted=true
       1 taken: acme/api#2
  1 unmatched: acme/api#3

An item goes to the first rule it matches; a later rule that matches it too shows 1 taken by #1: acme/api#1. To reorder, move the rules in the config.

Why a unit waits ​

awaywork plan says why a unit makes no work this run:

  • Waiting for review: it links an open awaywork PR. awaywork doesn't add to work you haven't read.
  • Waiting for your answer: the item's newest comment is awaywork's questions.
  • Waiting for your approval: of awaywork's plan on it, or of a report rule's result that waits.
  • Unchanged since run <id>: no item changed (updated, and for a sync its base's head) since a worker last finished this skill on it, so a review isn't redone every run. A continue is exempt.
  • Gave up after 3 attempts; next try on <date>: its chain didn't finish 3 runs in a row. It retries a week later, changed or not, and again a week after each failed try, so an error that fires nightly isn't retried nightly.
  • Skipped by you: awaywork skip <source:key> (e.g. github:acme/api#5) holds an item, and any unit it joins, until awaywork unskip or the --until date. plan --skipped skipped_by_you lists it with the --reason. Skips live in ~/.local/state/awaywork/skips.json.

run --unit runs a unit anyway, unchanged, skipped or given up; a given-up one runs as its one try.

Details:

  • An awaywork PR matches only rules whose where names ours, like the default fix on threads you left on it. That rule takes the unit even over a better-ranked linked item, and its draft stacks on the awaywork PR.
  • A GitHub issue's draft PR into the default branch says Closes it, which links them, so the issue waits with the draft.
  • awaywork's draft whose footer says it goes on there doesn't wait: the unit continues on it.
  • A PR awaywork pushed onto waits while its head is awaywork's push, unless that was a sync's clean merge.
  • An attempt is one chain, finished when every step that ran was done and no publish left anything behind. A failure, an error, a unit_minutes timeout or unpushed commits don't finish it; a plan report then a failed implement is one failure.
  • A finished attempt clears the count; another skill starts a new one. Skipped, dry-run and aborted units don't count, nor do stops the item didn't or may not have caused (quota, session limit, window end, a watchdog stop for low memory or disk). Attempts live in ~/.local/state/awaywork/attempts.json.

Run one unit ​

sh
awaywork run --unit api#1      # one unit, as plan names it
awaywork run --repo 'acme/*'   # only units in matching repos
awaywork run --rule 4          # only units of queue rule #4
awaywork report --list         # recent runs, to pick an id for report <id>
awaywork report --unit 2       # one unit in full: its files, PR body or report

--unit takes the item as plan shows it (api#1), its key (acme/api#1, github:acme/api#1) or the unit id (acme-api-1), in any case. It holds your terminal until the unit ends, hours sometimes; --detach hands it back at once, the output going to the run's run.log:

$ awaywork run --unit api#1 --detach
Started api#1 as run 20261109-095329; awaywork report 20261109-095329 shows it once it ends

To stop a detached unit, kill the pid in ~/.local/state/awaywork/run.lock: it ends as Ctrl-C would, report included.

  • A unit you name goes past limits.units, limits.units_per_repo and its rule's units; the rest of the plan stays capped.
  • A step of a rule's then runs its whole chain, from the first step.
  • It plans first, so a unit that can't start exits 1 saying why: not in the plan, the run lock taken, or no provider.
  • An item no rule takes needs a skill: --skill, detached too.
  • Outside your windows it's a present run with a lower session limit, and a provider whose quota awaywork can't read (a command provider without a probe) sits it out: run inside a window or add a probe.

--repo <glob> and --rule <n> (counting from 1, as plan shows) work on plan and run, and together both must hold. Caps and ceilings stay the full run's, but only matching units count: with limits.units: 3, --repo acme/api plans up to three acme/api units.

The run directory, ~/.local/state/awaywork/runs/<id>/, keeps the plan, the worker's log, its context files and the report. The id is the run's start time in UTC; old ones go after keep_runs.

The morning report ​

awaywork report opens the last run from its report.json: each provider's long window before and after against the ceiling, a row per unit with its result and a line of what it concluded, then Needs you and the skipped items. Here web#3 is selected and d just said why it did nothing:

☾ >_ awaywork  You're away, your agents work

Run 20261019-220012: 1 draft PR, 1 report, 3 units
2026-10-19 22:00:12 to 2026-10-19 23:47:40
away run (inside a window): session_max
claude: seven_day 5% to 17%, ceiling 42.9%; session 2% to 31%, stop at 90%

▾ Needs you 1
  ▾ tracker T 1
    T-4  Export invoices as CSV  add repo

▾ Units 3
       item  skill   status          result
  ▾ acme/api 2
    1  #1    fix     done, 14 turns  https://github.com/acme/api/pull/14
       Rate limits the public API with a token bucket per client key; bursts get a 429 instead of a…
    3  #2    review  done, 6 turns   report, verdict approve
       Approve: the session cache keys on the user id and expires with the token.
  ▾ acme/web 1
    2  #3    fix     done, 9 turns   nothing
       No code changes: the red check is the visual diff job, which fails on main too since #212.

▾ Skipped 2: 1 no_rule, 1 over_cap
  ▸ tracker T 1
  ▸ acme/api 1

⏎ read  o open  l log  d diff  s skip  a approve  ? help  q quit
diff: this unit left no diff

plan is the same view without l and d, since a plan has no logs or diffs. report opens at once too, a line per loading step, such as the run fetched from GitHub.

  • Items sit under their repo, or tracker and project key, so a row shows just #3.
  • A skipped item ends on what it asks of you (review PR, answer question, approve, add repo, ...) or why it waits (no rule, over cap, ...). Needs you sorts a repo's items by that, so PRs to review sit together.
  • The line under a skipped item is the rest of its reason, without the closest rule in Needs you; ⏎ has all of it. Rows run to the terminal's width, keeping that word on screen.
  • It opens on the first Needs you item, else the first unit, else the first skip, and leaves out empty sections; with nothing at all, it says why.
  • The footer dims keys with nothing behind them: d on a unit that committed nothing, l on a run from the runner, which keeps no logs.
KeyDoes
↑ ↓, j kmove
g G, Home Endfirst, last row
PgDn PgUp, Ctrl-D Ctrl-Ua screen down, up
→ ← Spaceunfold, fold, as ⏎ on a heading; ← on a row goes to its section
⏎page the unit in full (report --unit), or why an item is planned or skipped (plan --why), in $PAGER, else (or if it's cat) less -R -c -+F -+X, which repaints from the top and stays open on a short text
oopen the unit's PR, else its item; a skip waiting for review opens the PR it waits on
lpage the worker.log of the chain's last step
dpage the diff: the commits the unit published, else the step's own
sawaywork skip the item, after a y
aawaywork approve the item, after a y; there's no undo
?the keys
q, Esc, Ctrl-Cquit, also while it loads

Piped, in CI (CI set), or with --json, --list, --unit or --skipped, it prints text, so awaywork report | cat prints the view, then the quota and how to dig in:

$ awaywork report | cat
Run 20261019-220012: 1 draft PR, 1 report, 3 units
[...]
Quota
  away run (inside a window): session_max
  claude: seven_day 5% to 17%, ceiling 42.9%; session 2% to 31%, stop at 90%

awaywork report 20261019-220012 --unit <n|key>    shows one
awaywork report 20261019-220012 --skipped [kind]  lists the skipped items

report --unit <n> prints one unit in full, as ⏎ pages it: links, each step with its provider and what it left when there are several, the files still there (none on a run from the runner), then its PR body or report. It takes the row number, the unit id (a step's gives its chain) or an item:

$ awaywork report --unit 2
2  web#3  WIP: new billing page
  skill   fix
  status  done, 9 turns
  result  nothing
  item    https://github.com/acme/web/pull/3
  files   ~/.local/state/awaywork/runs/20261019-220012/units/acme-web-3/1-fix/worker.log
          ~/.local/state/awaywork/runs/20261019-220012/units/acme-web-3/out/pr.md

Fix the billing page build
[...]
  • An all-digit item key, like an Asana gid, wins over a row number.
  • A name that fits two units (api#1 under two owners) is refused with each one's source:key, here and in run --unit and plan --why.
  • A long reason, like a failed setup's output, gets its first line in the row, all of it under --unit.
  • A unit with then steps is one row, its chain in the skill column.

Also:

  • report --skipped [kind] lists the skipped items as plan --skipped does; report --json prints the run as JSON.
  • report --list lists recent runs with their units, PRs and reports, and report <id> prints one; inside a control repo they include the runs GitHub Actions uploaded.
  • During a run there's no report yet: report lists the steps done, the one working and its worker.log path, to tail -f.
  • The run dir also keeps report.md, the run as markdown: units with every step under its chain and a summary line each, Needs you, the skips folded by kind, each report folded under its unit. GitHub Actions puts it in the job summary and notify gets it. A run from before report.json prints its report.md.

Stats ​

awaywork stats adds up every run that kept a units.json, per rule (by its place in that run's queue), skill and provider: units, how many were done, failed or stopped, the share of the long quota window their workers used, and PRs opened. --json prints the same.

  • The quota share is an estimate: it starts at the reading before the unit (the plan's probe, then that provider's previous unit), includes other use of the account meanwhile, and is - when the window reset mid-unit or the worker read no quota.
  • A chain's steps count one by one, and only the first carries the chain's PR, so later skills' rows show no PRs.
  • units.json is written when the run ends, so a killed run, or an older one, has none and is left out.