Skip to content

With an AI agent ​

Let your coding agent write your where clauses, field names and your tracker's spelling of In Progress included: the away skill asks what you want offloaded, tries its rules on your real PRs, issues and tasks, shows what each would take tonight, and writes only what you say yes to.

In Claude Code the plugin adds a pane beside the chat too: see /away in Claude Code.

Codex and friends ​

The same skill ships in the npm package, in plugin/skills/away/, in the Agent Skills format. Codex reads the Claude Code marketplace too:

sh
codex plugin marketplace add AndreaProvenzale/awaywork
codex plugin add awaywork@awaywork

It shows up in Codex's skill list as awaywork:away; ask Codex to use it by name. Its longer routes, setup.md, queue.md and suggest.md, sit beside its SKILL.md and are read only when a route needs one.

Any agent that loads skills from a folder can take it from the installed package, e.g. ~/.agents/skills, which Codex reads as well:

sh
mkdir -p ~/.agents/skills
ln -s "$(npm root -g)/awaywork/plugin/skills/away" ~/.agents/skills/away

No skills support? Tell the agent to read away/SKILL.md and follow it.

Prompt to paste ​

For a setup from scratch, before there's a config:

text
Set up awaywork (https://andreaprovenzale.github.io/awaywork/llms.txt)
for me. Read the docs first. Find which of claude, codex and agent
(Cursor) I have installed and logged in, and which GitHub repos I work on (gh). Ask me
which repos and which Asana workspace to include and how much quota a
run may use, then write the config, validate it and show me the plan.
If a source needs a token, tell me to run awaywork secret <NAME>
instead of asking me for it. Don't start a run or install a schedule until I say so.

For agents ​

Machine-readable docs:

URLWhat
llms.txtIndex of every page, as Markdown links
llms-full.txtAll pages in one file
<page>.mdAny page as Markdown, e.g. guide/configuration.md
config.schema.jsonThe config's JSON Schema; awaywork config schema prints the installed version's
awayThe /away skill: status, why an item did or didn't run, and which of the files below handles the rest
setup.mdA first config: whose work and which logins, where it runs, repos from recent sessions, trackers, a checked first queue
queue.mdWriting and checking rules on real items
suggest.mdCandidate rules from the user's own sessions and PRs, asked for every run

Setting up ​

  1. npm install -g awaywork; check claude --version, codex --version, agent --version (Cursor, which also needs CURSOR_API_KEY in the env file), gh auth status.
  2. awaywork init --yes writes ~/.config/awaywork/config.yml without a terminal: the installed providers, github when gh is logged in (repos <login>/*), its default rules for those sources and a 01:00-07:00 window. It won't replace a config without --force.
    • --provider, --source and --window override what it detects (init).
    • Asana is skipped with a note unless ASANA_TOKEN is set; then it takes the first workspace and every project with the user's tasks. Linear likewise needs LINEAR_API_KEY. Jira is skipped: it needs a site and an email.
    • Cursor counts as installed only with CURSOR_API_KEY set; --provider cursor takes it anyway. Where it's the only agent, --yes without either stops, naming the missing key.
    • To go further, edit the file from Configuration and the reference. awaywork sources asana --json gives the workspace and project gids and the real section names for where; sources linear, sources jira (once the config has its site and email) and sources github do the same, never showing the token.
  3. Secrets go in ~/.config/awaywork/env (NAME=value lines, mode 600), never the config. The user puts them there with awaywork secret ASANA_TOKEN (a hidden prompt; in Claude Code, ! pbpaste | awaywork secret ASANA_TOKEN after copying it). Don't ask for them in the chat, and don't read that file or other tools' credentials.
  4. awaywork doctor until the config's line isn't FAIL. Its gh login and <provider> login lines name the account each run uses; with several on a machine, the config pins them (Which login). Without a config it still lists each agent CLI: ok with its version, warn when not installed or, for Cursor, CURSOR_API_KEY unset.
  5. For the queue, follow the skill. Run awaywork plan and show the user. With stdin and stdout both a terminal, plan and report open an interactive view; piped (| cat) or with CI set, they print text.

What each command does ​

CommandEffect
config path, config schema, skills list, skills list --json, report, schedule statusRead-only, local
plan, doctorRead-only on sources and forge; probe each provider's quota (one tiny model call for Claude)
plan --rules, plan --rules --jsonRead-only on sources and forge; probe no provider
sources [id]Read-only on sources; prints no token
skills eject <name>Copies a skill into the user's skills dir
run --dry-runClones repos and writes workspaces; no agent, nothing pushed
run, run --unit <id>, run --unit <id> --detach, run --unit <id> --skill <name>Runs agents on the user's quota; pushes branches and opens draft PRs. --detach returns once the unit started; --skill runs a skill on an item no rule takes. Ask first
schedule installInstalls a scheduled job, or writes a workflow with --with github-actions, or a container's files with --with docker. Ask first
init --yesWrites the config from detected defaults; --force replaces one
secret <NAME>Writes the env file from a hidden prompt or a pipe; prints no value. The user runs it, not you
initInteractive; needs a terminal. It opens Claude Code on /away

awaywork <command> --help and the CLI reference list every option.

plan --json ​

awaywork plan --json prints one object: queue, allowances (per provider), units, skipped and warnings. Items leave out their raw source payload.

A skipped entry is { item, kind, reason }, plus url when it waits on an awaywork PR for review (the PR to open, maybe not the item) or on an answer or approval (the item awaywork asked or posted its plan on). The kinds the user can act on have needsYou: true:

kindneedsYouWhat it means
waiting_for_reviewyesreview the awaywork PR
waiting_for_answeryesanswer awaywork's questions on the item
waiting_for_approvalyesapprove the plan or result awaywork posted
invalid_planyesfix the plan
store_failedyesfix the store that couldn't read a post's files back
all_tasks_doneyesclose or move the card whose tasks are all done
gave_upyesread the failed logs
no_repoyesgive the item a repo
invalid_branch, refused_deliveryyesfix the rule
draft_moved, continue_capyesfinish, mark ready or close awaywork's draft that moved or said continue 3 times
no_rule, over_cap, unchanged, skipped_by_younothe config doing its job
unlisted_reponothe item's repo is not in repos
approvednoa report rule is done with the item: you approved its result, or it went ahead
fanned_outnoa card whose plan became tasks
waiting_for_tasknoa task waiting for another's PR to merge, or to open, for a check on it to pass, or for your approval of another task's result
task_merged, task_donenoa task whose PR merged, or that reports and whose done result is on its card
continues_laternoa continue a soon run leaves to the next window run
runningnoanother of the daemon's runs is working on it

Plans and tasks:

  • A card's taskPrs holds its tasks' PRs by task id, with checks: each check a task's after names, as { state, url }: state is passed, pending or failing, url the check's link when the forge gives one (untrusted); missing when not reported.
  • A task's item.task has its card as parent, its id and skill, plan (the plan's tasks, each with after (opened, merged or a check's name), repo and ships), contract when there is one, and onto, the task whose PR it stacks on. Its item.fields.repo is its own repo.
  • A unit stacked on a PR another unit of the run opens has after, that unit's id; one waiting for tasks in other repos to open their PR earlier in the run has waitsFor, their task ids.
  • A unit that goes on from an earlier run has continued, its continue count so far. On awaywork's own draft it also has resume: url, number, status (continue or ask), head (where awaywork left it) and from (the commit the draft's commits start after).

The other --json outputs ​

  • skills list --json: skills, each { name, deliver, pickable }: the delivery it defaults to, and whether run --unit --skill can run it on one item.

  • plan --rules --json: the queue against the items the sources return now, reading no quota, attempts or caps (so plan --why <key> says what a run would really do). rules gives each rule's rule number, skill, summary, the items it takes (taken, with plan: true on a card its deliver: plan rule keeps though its where no longer matches) and those another rule takes (takenBy, by that rule's number); then unmatched (each with a reason naming the closest rule and the conditions it failed) and warnings. Items are references: source, key, title, url. On a repo with one review rule:

    json
    {
      "rules": [{ "rule": 1, "skill": "review", "summary": "type=pr review_requested=true trusted=true", "taken": [], "takenBy": [] }],
      "unmatched": [
        {
          "source": "github",
          "key": "acme/api#134",
          "title": "Review smoke: fix the typo in README",
          "url": "https://github.com/acme/api/issues/134",
          "reason": "matched no rule; closest #1 review: type is issue, wants pr; review_requested is unset, wants true"
        }
      ],
      "warnings": []
    }
  • sources [id] --json: one object keyed by source id, of what each one's credentials can see. github has login and orgs; asana workspaces, each with gid, name, projects (gid, name) and sections; linear teams, each with key, name and states; jira projects (key, name) and statuses. A source with nothing to list (bitbucket, a custom one) is left out without an id, an error with one. A source that can't tell, say with its token unset, goes to stderr as <id>: <why> (naming the variable and the env file) and makes it exit 1; without an id, the others still print.

  • doctor --json: an array of { status, what, detail }, status being ok, warn or FAIL; it exits 1 on any FAIL, as without --json.

  • report --json: the run's runId, dryRun, startedAt, finishedAt, plan, results, quotas and warnings, from its report.json.

    • With no id it's the last run that has one (report --unit and --skipped pick the same), so a run still going, or one that died, doesn't take its place. With none, or an id of a run without one, it exits 1.
    • Items are references (source, key, title, url), plus type and, when it's yours, mine on a skipped one. Skipped entries have kind and needsYou as in plan --json, except in runs from before skips had kinds.
    • Each started step has files, relative to the run dir: log, report and diff (its own commits) from its folder. A slice's first step, which publishes it, also has sliceBody and sliceDiff from out/ (out-2/ for a stacked slice and so on): the PR body or push summary (the joined report when the slice published reports) and the commits it published, or would have if the publish failed.
    • A key is there only when its file was; a run from the runner has only report.md, report.json and units.json, so check a path exists before opening it.
    • summary is the first paragraph of sliceBody, else of report; the PR it opened or pushed onto is outcome.url. A fix that found nothing to commit, trimmed:
    json
    {
      "status": "done",
      "outcome": { "kind": "none", "reason": "nothing" },
      "summary": "No code changes: both red checks are unrelated to this diff.",
      "files": { "log": "units/acme-api-5/1-fix/worker.log", "sliceBody": "units/acme-api-5/out/pr.md" }
    }