> ## Documentation Index
> Fetch the complete documentation index at: https://platform.atlan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sync skills from GitHub

> Publish repository-managed skills to an Atlan workspace with a copyable GitHub Actions workflow.

# Sync skills from GitHub

Use GitHub Actions to publish skills whenever their source changes on `main`.
The repository remains the source of truth, while Atlan records the repository,
commit, and path for each published version. The workflow below is a copyable
CI script. It does not depend on a published Atlan GitHub Action.

## Before you start

You need a GitHub repository with Actions enabled, an Atlan workspace ID, and a
dedicated Atlan API key whose identity can publish to that workspace. Each skill
must be a direct child of one repository directory and include a case-sensitive
`SKILL.md` file:

```text theme={null}
skills/
├── meeting-brief/
│   ├── SKILL.md
│   └── references/
└── release-notes/
    └── SKILL.md
```

## 1. Declare what to publish

Create `.atlan/package.json` at the repository root:

```json theme={null}
{
  "name": "example-skills",
  "configVersion": 1,
  "publishConfig": {
    "workspaces": ["workspace_01example"],
    "directory": "skills",
    "skills": "*",
    "trigger": "ci",
    "branch": "main"
  }
}
```

| Field           | Value                                                                                                                  |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `configVersion` | The current manifest version: `1`.                                                                                     |
| `workspaces`    | One or more destination workspace IDs. Use the older `workspace` form only for one destination; never set both fields. |
| `directory`     | One existing, repository-relative directory containing the skill folders. Symlinks are rejected.                       |
| `skills`        | `"*"` for every discovered folder, or a list such as `["meeting-brief"]`.                                              |
| `trigger`       | `"ci"` for this workflow.                                                                                              |
| `branch`        | The only branch allowed to publish. It defaults to `main` for CI.                                                      |

The manifest rejects unknown fields. In particular, use `directory` and
`skills`; `publishConfig.paths` is not supported.

## 2. Add the API key to GitHub

In the GitHub repository, open **Settings → Secrets and variables → Actions**
and create this repository secret:

| Name            | Value                        |
| --------------- | ---------------------------- |
| `ATLANAI_TOKEN` | The dedicated Atlan API key. |

Never add the API key to `.atlan/package.json`, the workflow file, logs, or
screenshots. The identity behind the key must be a member of every destination
workspace declared in the manifest.

## 3. Add the workflow

Create `.github/workflows/atlan-skill-sync.yml`:

```yaml theme={null}
name: Sync skills to Atlan

on:
  push:
    branches: [main]
    paths:
      - 'skills/**'
      - '.atlan/package.json'
      - '.github/workflows/atlan-skill-sync.yml'

concurrency:
  group: atlan-skill-sync-${{ github.ref }}
  cancel-in-progress: false

permissions:
  contents: read

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0

      - name: Install atlanai
        env:
          ATLANAI_CHANNEL: preview
        run: |
          set -euo pipefail
          curl --fail --silent --show-error --location --retry 3 --retry-connrefused \
            https://agentgateway.atlan.engineering/install.sh -o "$RUNNER_TEMP/atlanai-install.sh"
          sh "$RUNNER_TEMP/atlanai-install.sh"
          atlanai version

      - name: Publish skills
        env:
          ATLANAI_TOKEN: ${{ secrets.ATLANAI_TOKEN }}
          CHANGED_SINCE: ${{ github.event.before }}
        run: |
          set -euo pipefail
          args=(skill publish --ci)
          if [ -n "${CHANGED_SINCE:-}" ] && [ "${CHANGED_SINCE}" != "0000000000000000000000000000000000000000" ]; then
            args+=(--changed-since "${CHANGED_SINCE}")
          fi
          atlanai "${args[@]}"
```

Change `skills/**` when the manifest uses another directory. Keep
`fetch-depth: 0`: the CLI needs complete history to record the first and most
recent source commits accurately.

The script downloads the installer before it runs it. Review any change to that
installer origin as a CI dependency change; do not replace it with a
`curl | sh` pipeline. The API key remains only in the GitHub secret.

## What the workflow does

1. Validates `.atlan/package.json` and the allowed publish branch.
2. Finds skill folders under `publishConfig.directory`.
3. Publishes skills changed since the push's base commit. A first push, an
   unresolvable base commit, or an all-zero base publishes every declared skill.
4. Creates a skill for a new repository path or appends a version when the
   Registry already has that repository and path.
5. Skips unchanged content, waits for the Registry security scan, and fails the
   job when the scan blocks a skill.

The CI runner has no local tracking database. Reconciliation uses the repository
and path, not a skill name, because names can be edited or repeated.

## Verify the first sync

Commit the manifest and workflow to `main`. Confirm that the **Sync skills to
Atlan** workflow completes, the skills appear in the intended workspace, and a
skill profile shows its repository, commit, and path.

If a scan remains pending after 60 seconds, the CLI prints follow-up `skill get`
and `skill runs` commands. Use those commands to confirm the final scan state
before treating a skill as available.

## Optional workflow controls

Add one of these arguments to the `args` array only when the override is
reviewed for that run:

| Argument                  | Behavior                                                              |
| ------------------------- | --------------------------------------------------------------------- |
| `--workspace <id>`        | Override the manifest destinations. Repeat it for several workspaces. |
| `--branch-guard <branch>` | Override the allowed publish branch.                                  |
| `--prune`                 | Archive repository-bound skills removed from the checkout.            |

`--prune` archives artifacts, so enable it only after confirming the expected
removed skill directories. It preserves versions and traces.

## Run the same publish locally

```bash theme={null}
atlanai skill publish
atlanai skill publish --changed-since HEAD~1
atlanai skill publish --workspace workspace_01example
atlanai skill publish --ci
```

`.atlan/package.json` is required for `skill publish`. For one local skill
without a repository manifest, use [Publish skills with the CLI](/guides/skills/publish-with-cli).

## Troubleshooting

**`unknown field "paths"`** — replace `publishConfig.paths` with the supported
`directory` and `skills` fields.

**`This checkout is shallow`** — set `fetch-depth: 0` on `actions/checkout`.

**`No such resource, or it is not visible to you`** — confirm the workspace ID
and that the identity behind `ATLANAI_TOKEN` can publish there.

**Publishing is restricted to `main`** — merge the change to the manifest's
configured branch.
