id: atlassian
category: feature
displayName: Atlassian
description: 'Rovo Dev (`acli rovodev`), Teamwork Graph (`twg`) and Forge (`forge`) CLIs sharing one Atlassian account. Auth persists across rebuilds.'
documentationURL: https://developer.atlassian.com/cloud/
options:
  rovodev:
    type: boolean
    default: true
    description: 'Install acli (with the Rovo Dev agent).'
    surface: yml
  twg:
    type: boolean
    default: true
    description: 'Install twg (Teamwork Graph CLI).'
    surface: yml
  forge:
    type: boolean
    default: true
    description: 'Install the Forge CLI (`forge`) for building Atlassian apps.'
    surface: yml
  instance:
    type: string
    default: ''
    description: 'Atlassian site host (`yoursite.atlassian.net`); required by twg.'
    surface: env
  email:
    type: string
    default: ''
    description: 'Atlassian account email; used with `apiToken` for non-interactive login.'
    surface: env
  apiToken:
    type: string
    default: ''
    description: 'Atlassian API token for twg and Forge (id.atlassian.com, Security, API tokens). Rovo Dev does not accept this one, see `rovodevToken`.'
    surface: env
  rovodevToken:
    type: string
    default: ''
    description: 'Rovo Dev scoped API token, which is a different token from `apiToken` (id.atlassian.com, Security, create an API token with scopes). acli rejects a classic token with a bare "authentication failed", so the two cannot share one variable.'
    surface: env
  bitbucketToken:
    type: string
    default: ''
    description: 'Bitbucket access for twg and repo clone: an Atlassian API token with `read/write:repository:bitbucket` scopes (app passwords retire 2026-06-09). Leave empty to reuse `apiToken` when that token already carries the Bitbucket scopes.'
    surface: env
feature:
  version: 1.3.3
  # Installs a global npm package, so it has to run after the node
  # feature: otherwise npm resolves the version against the Node the
  # runtime image ships, which a pinned `node:<major>` then replaces.
  installsAfter: [ghcr.io/devcontainers/features/node]
  # `.config/@forge` carries the Forge CLI's own settings, including the
  # analytics consent. Without it the consent prompt returns after every apply,
  # and a prompt on stdin is where an agent's `forge` call stops dead.
  persistentHomePaths:
    [.config/acli, .rovodev, .config/twg, .config/@forge, .agents]
  vscodeExtensions: [Atlassian.atlascode]
  # Forge and twg are both keychain-free in a container: instead of a
  # `login` step (which needs libsecret, or a TTY for twg's OAuth),
  # Atlassian's documented path is env vars read at command time. We hand
  # them to the workspace runtime env from the shared account options,
  # each gated on its own toggle. Sibling of a service's connectionEnv
  # (ADR 0021).
  #   - Forge reads FORGE_EMAIL / FORGE_API_TOKEN.
  #   - twg reads TWG_USER / TWG_SITE / TWG_TOKEN (+ optional
  #     TWG_BBC_TOKEN for Bitbucket). Recent twg makes `twg login`
  #     OAuth-only and it aborts without a TTY, so these env vars are the
  #     only non-interactive auth path; there is no login hook.
  #   - Rovo Dev DOES have a login step (acli keeps its own credentials), but
  #     the token reaches it through the environment rather than being baked
  #     into the feature layer: the layer is cached, so a baked token would
  #     survive a rotation and `apply` would keep logging in with the old one
  #     (ADR 0018). The post-create hook reads this var at container start.
  workspaceEnv:
    - whenOption: forge
      vars:
        FORGE_EMAIL: '${email}'
        FORGE_API_TOKEN: '${apiToken}'
    - whenOption: twg
      vars:
        TWG_USER: '${email}'
        TWG_SITE: '${instance}'
        TWG_TOKEN: '${apiToken}'
        TWG_BBC_TOKEN: '${bitbucketToken}'
    - whenOption: rovodev
      vars:
        ATLASSIAN_ROVODEV_EMAIL: '${email}'
        ATLASSIAN_ROVODEV_TOKEN: '${rovodevToken}'
        # The site Rovo Dev bills against. Same `instance` twg gets as
        # TWG_SITE; without it the first `acli rovodev run` asks for it on
        # stdin, which is where an agent's first Rovo Dev call stops.
        ATLASSIAN_ROVODEV_SITE: '${instance}'
briefing:
  - whenOption: rovodev
    text: 'Atlassian Rovo Dev, invoked via `acli rovodev`. Logged in at container start from its own scoped token (ATLASSIAN_ROVODEV_TOKEN), which is a different token from the one twg and Forge use. If a command reports no authentication, the token needs replacing on the host; you cannot fix it from in here.'
  - whenOption: twg
    text: 'Atlassian Teamwork Graph CLI (`twg`) — work-data access across Jira, Confluence, Bitbucket, JSM and Assets. Pre-authenticated. Sub-skills cover status rollups, engineering work, ops health and context discovery.'
  - whenOption: forge
    text: 'Atlassian Forge CLI (`forge`) for building and deploying Forge apps. Authenticated via FORGE_EMAIL / FORGE_API_TOKEN from the shared account (no `forge login` needed in the container).'
presets:
  twg:
    rovodev: false
    twg: true
    forge: false
  rovodev:
    rovodev: true
    twg: false
    forge: false
  forge:
    rovodev: false
    twg: false
    forge: true
