Sources
Each source reads your own items from one place:
| Source | Reads | You set |
|---|---|---|
github | Your PRs, PRs awaiting your review, issues assigned to you, in the repos you list, plus any search (label:awaywork, mentions:@me) | {} is enough; optional search |
asana | Your incomplete tasks in the workspace, optionally only some projects | workspace gid; optional projects, repo_map |
linear | Your issues neither completed nor canceled | Optional repo_map |
jira | Your unresolved issues | site, email; optional cloud_id (scoped token), jql (no ORDER BY), repo_map |
routines | Each routine's latest occurrence | Routines |
| any other name | Your command's JSON | Custom sources |
Each also reads its finished items when a rule asks. The rest, defaults and token_env names included, is in the reference. Every source takes an every for run: soon; all but github and routines a link.
awaywork sources <id> lists, read-only, the ids and names your keys and where take (--json for scripts):
$ awaywork sources linear
linear:
teams:
- key: ENG
name: Engineering
states:
- Todo
- In Progress
[...]github lists your login and orgs; asana the workspaces, then the configured one's projects and sections; jira the projects and statuses, once site and email are set.
The forge, where the repos live and PRs open, is its own top-level key, GitHub unless you say otherwise:
forge: github # the default; leave it out
# forge: bitbucket # Bitbucket Cloud, see below
# forge: { github: { host: github.acme.com, user: octocat } } # GitHub Enterprise, or a pinned gh accounthost is a GitHub Enterprise host gh is logged in to; user is in Which login. A config has one forge. GitHub items come only with sources.github: without it, GitHub is still where your trackers' work opens its PRs.
Experimental
forge.github.host has only run in tests so far, never against a real GitHub Enterprise. init, doctor and artifact downloads still use gh's default host. Tried it? Open an issue with how it went.
Tracker tokens
awaywork only reads with a tracker token, except for on_done, questions and plans, and never hands it to the agent unless you list it in an MCP server's secrets.
- Asana has no read-only token: make one just for awaywork, so you can revoke it alone.
- Linear: a personal API key (Settings > Account > Security & access), read-only when offered, or with write for those three.
- Jira Cloud: an Atlassian API token (id.atlassian.com > Security > API tokens). Prefer one with scopes, app Jira,
read:jira-workpluswrite:jira-workfor those three:/awaythen finds thecloud_id, and awaywork callsapi.atlassian.com, as scoped tokens require. An unscoped token can do anything you can. Tokens last at most a year. - Jira custom fields sharing a name are keyed by name and id:
fields.Team (customfield_10040).
Context commands
A built-in source's context command fetches what an item points at, a Sentry issue or a runbook, with secrets the agent never gets:
sources:
github:
context:
command: ./fetch-sentry.sh # reads $AWAYWORK_ITEM_URL, writes $AWAYWORK_CONTEXT_DIR/sentry.md
secrets: [SENTRY_TOKEN] # kept out of the agent's envIt runs per item before the worker, in the config's folder, never the clone, with AWAYWORK_ITEM_KEY, AWAYWORK_ITEM_URL and AWAYWORK_ITEM_FILE (the item as JSON). What it writes to $AWAYWORK_CONTEXT_DIR lands in .away/context/<item>/extra/ as is, so never write a secret there (curl -v into a file, say). Its limits are in What runs in the clone. A custom source does this in its own command.
Bitbucket and Jira
Code on Bitbucket Cloud, tickets in Jira? Set forge: bitbucket and list at least one repo, and draft PRs open on Bitbucket:
forge: bitbucket
repos:
acme/*: # the workspace is literal, the name globs
sources:
jira:
site: acme.atlassian.net
email: me@acme.com
repo_map: { ENG: acme/api } # project key -> workspace/name on BitbucketIt goes through Atlassian's twg CLI, and git over SSH with your keys. You need twg logged in (twg setup bitbucket, or a token in TWG_BBC_TOKEN) and an SSH key git can use without a passphrase prompt, since launchd and cron have no terminal; a key in an agent your scheduler sees works too. doctor checks both (details at the end of this section).
A run ends as on GitHub, with a draft PR whose footer links back to the item. away/{key} puts the Jira key in the branch, which Jira's development panel links on. Plans work too: twg finds task PRs, reads files a task ships, and the build statuses a task waits on. Not yet:
- Bitbucket's own items: there is no Bitbucket source, so no fix or review rules on its PRs. Your open PRs still link to items.
deliver: push: refused, since twg reads neither branch restrictions nor auto-merge.deliver: pending_review: refused; GitHub only.- Going on with its own draft: a draft that says
continue, or asked, is yours to finish (Continue). - GitHub Actions or a container:
schedule installrefuses both; use launchd, systemd or cron. - Fork PRs: no pull refs to fetch, so the unit fails.
- The
githubsource: refused withforge: bitbucket; one forge per config.
What doctor prints:
✔ twg: 1.3.8
✔ twg acme
✔ git over ssh: acme/apitwg acme is twg bb workspace get per workspace; git over ssh a git ls-remote with -o BatchMode=yes added to git's ssh command (GIT_SSH_COMMAND, else core.sshCommand, else ssh; a GIT_SSH wrapper runs as is), so a prompting key fails here, not in a scheduled run. It warns when twg keeps its login anywhere but a file (Safety).
Routines
Work with no ticket, only a day: every Monday you triage Sentry. A routine is an item that comes due on the clock, so rules, plan and attempts treat it like any other:
sources:
routines:
sentry-triage:
days: [mon] # sun to sat; every day when unset
at: "09:00" # local time; or a list: ["09:00", "14:00"]
repo: acme/api # required: where the work happens
title: Triage last week's Sentry issues
description: Group new issues, link duplicates, draft fixes for the top three.
queue:
- skill: triage
source: routines
where: { name: sentry-triage }
deliver: report
run: soon # within minutes of 09:00, not at the next windowEach is one task, its latest occurrence, keyed <name>-<YYYYMMDD>-<HHMM> in local time: branch away/sentry-triage-20261026-0900. plan lists when each comes due next, and --why which occurrence an item is:
$ awaywork plan --why sentry-triage-20261026-0900
routines sentry-triage-20261026-0900 Triage last week's Sentry issues
https://github.com/acme/api
routine sentry-triage, due mon 2026-10-26 09:00; next mon 2026-11-02 09:00
[...]Details:
- A machine asleep all week wakes to one item, not a backlog. Once a unit on it finishes, it's unchanged until the next occurrence, a new item.
- It's yours (
mine), itsurlthe repo's page. Rules matchname,repo,createdandupdated(both the occurrence). - Any name but
contextandevery. - On GitHub Actions, times are the workflow's
TZ. Withoutrun: soonit waits for a window: Monday's 09:00 runs Tuesday at 01:00 with the default one. - No tracker to write to:
on_doneanddeliver: planare refused, and results or questions stay in the report;notifycan send them on. - It takes a
contextcommand.initwrites no rules for routines: write yours.