name: CI Agent Skills Drift # When a PR changes the app-development surface (twenty-sdk, create-twenty-app, # twenty-client-sdk, or the shared manifest types), an agent checks whether the # canonical skill content under packages/twenty-agent-skills is impacted and, # only when it is, posts a single sticky comment with its findings. # # This is the skills counterpart to ci-app-docs-drift.yaml: the same source # changes that stale the docs also stale the guidance agents follow. on: pull_request: permissions: contents: read id-token: write concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: changed-files-check: uses: ./.github/workflows/changed-files.yaml with: files: | packages/twenty-sdk/** packages/create-twenty-app/** packages/twenty-client-sdk/** packages/twenty-shared/src/application/** packages/twenty-shared/src/types/** agent-skills-drift-check: needs: changed-files-check # Secrets are unavailable on fork PRs; skip there and on bot PRs. if: >- needs.changed-files-check.outputs.any_changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.user.type != 'Bot' timeout-minutes: 30 runs-on: ubuntu-latest permissions: contents: read pull-requests: write id-token: write steps: - name: Checkout repository uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: fetch-depth: 0 - name: Run agent skills drift agent id: drift-agent uses: anthropics/claude-code-action@ac7e24bf2938964b8ab203e417a2773802392ddd # v1.0.146 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} claude_args: | --max-turns 60 --json-schema '{"type":"object","properties":{"hasDrift":{"type":"boolean"},"summary":{"type":"string"}},"required":["hasDrift","summary"]}' --allowedTools "Bash(git diff *),Bash(git log *),Bash(git show *),Bash(grep *),Bash(cat *),Bash(ls *),Bash(find *),Bash(head *),Bash(tail *),Bash(gh pr comment *)" prompt: | You are the agent-skills drift checker for the twenty repository. A pull request changed files in the app-development platform. Your job is to decide whether the skill guidance under `packages/twenty-agent-skills/` is impacted, and report your findings as ONE pull request comment. These skills tell coding agents how to build Twenty apps. When they go stale an agent confidently runs a command that no longer exists, so wrong guidance is worse here than a missing doc page. ## Canonical source only `packages/twenty-agent-skills/skills/` and `packages/twenty-agent-skills/references/` are the canonical content. `packages/twenty-agent-skills/dist/` is generated for distribution and is not committed to main. Report the canonical file that needs an edit. ## Step 1 — Understand the change The PR branch is checked out with full history; the base branch is `origin/${{ github.base_ref }}`. Inspect what the PR changes however you see fit. Only these kinds of changes are skill-relevant: - CLI commands, subcommands, flags, defaults, or help text (`packages/twenty-sdk/src/cli/commands/**`) - `define*` function signatures, config properties, validation rules, or their warnings (`packages/twenty-sdk/src/sdk/define/**`) - Enum / string-union values and manifest types (`packages/twenty-shared/src/application/**`, `packages/twenty-shared/src/types/**`) - Exports added/removed/renamed in the `exports` maps of `twenty-sdk` or `twenty-client-sdk` package.json, or in their public entry points - Front-component runtime hooks and host API (`packages/twenty-sdk/src/sdk/front-component/**`) - The scaffold template (`packages/create-twenty-app/src/constants/template/**`) and scaffolder flags/prompts (`packages/create-twenty-app/src/cli.ts`, `create-app.command.ts`) - Environment variables injected into logic functions or front components - Error codes surfaced to app developers - Default ports and instance URLs used during development Internal refactors, tests, and implementation-only changes are NOT relevant — if the changes contain only those, say so and stop. ## Step 2 — Map to skill content Use this mapping to know which files to check (read the actual files, all paths relative to `packages/twenty-agent-skills/`): | Source area | Skill content | |---|---| | CLI commands (`src/cli/commands`) | `references/manage-app/cli-and-sync.md`, `skills/manage-app/SKILL.md`, `references/concepts/operating-rules.md` | | Scaffolder flags, prompts, template | `skills/create-app/SKILL.md`, `references/develop-app/app-structure.md` | | `defineObject`/`defineField`/relations/indexes | `references/develop-app/data-model.md` | | `defineApplication`/roles/install hooks/variables | `references/concepts/how-apps-work.md`, `references/publish-app/prepare-for-app-store.md` | | Logic functions, triggers, connections, agents/skills | `references/develop-app/logic.md` | | Workflows and their lifecycle | `references/develop-app/workflows.md` | | Views, navigation, page layouts, command menu | `references/develop-app/layout.md`, `references/develop-app/standalone-pages.md` | | Front components, SDK imports, runtime hooks | `references/develop-app/front-components.md`, `references/design/front-component-ui.md` | | Test layout, test target ports | `references/develop-app/tests.md`, `references/concepts/operating-rules.md` | | Publish/install/deploy, versioning | `references/publish-app/prepare-for-app-store.md`, `skills/publish-app/SKILL.md` | | MCP endpoints, transport, auth | `references/use-twenty-mcp/setup.md`, `references/use-twenty-mcp/result-formatting.md` | | Enum value sets (FieldType, ViewType, availabilityType, NavigationMenuItemType, ...) | the reference documenting that value set (search for the enum name) | Two extra checks specific to this package: - `scripts/validators/` encodes cross-document contracts as literal string fragments (exact commands, ports, section headings). A renamed command or changed port can make a validator assert something no longer true, so check whether the change invalidates a fragment there. - `references/concepts/operating-rules.md` is the single source of truth for the durable rules and names exact commands. A command rename lands here. Also check whether the PR already updates the impacted files — if it does, verify the update matches the code change. ## Step 3 — Report If there is NO skill impact, do NOT post or create any comment. Skip the comment entirely and go straight to Step 4. Only when the skills are impacted, post exactly one comment on PR #${{ github.event.pull_request.number }} with: `gh pr comment ${{ github.event.pull_request.number }} --edit-last --create-if-none --body ...` (this updates the previous drift-check comment in place on subsequent runs). Start the comment body with the marker ``. Comment format: - Title line: `### Agent skills drift check` - A table with columns **Change** (what changed in the code), **Skill file** (repo-relative path, canonical only), **Status** (`✅ already updated in this PR` / `⚠️ needs update`), and **Suggested fix** (one concrete sentence, e.g. the exact command to replace). - When any row needs an update, end with one line reminding the author to run `npx nx run twenty-agent-skills:validate` after editing the canonical content. - Be terse. No preamble, no sign-off. Only report genuine drift — if unsure whether something is user-facing, say it's uncertain rather than asserting. ## Step 4 — Return the verdict After posting the comment, return your final answer as the structured output the CI gate consumes: - `hasDrift`: `true` if at least one impacted skill file still needs updating (drift is NOT fully resolved by this PR); `false` if there is no skill impact, or every impacted file is already correctly updated in this PR. - `summary`: one terse sentence describing the verdict. Environment: GH_TOKEN is available for `gh`. The PR branch is checked out. settings: | { "env": { "GH_TOKEN": "${{ secrets.GITHUB_TOKEN }}" } } - name: Gate on drift verdict if: always() env: AGENT_OUTCOME: ${{ steps.drift-agent.outcome }} STRUCTURED_OUTPUT: ${{ steps.drift-agent.outputs.structured_output }} run: | if [ "$AGENT_OUTCOME" != "success" ]; then echo "::error::Agent skills drift checker did not complete (agent step outcome: $AGENT_OUTCOME)." exit 1 fi if [ -z "$STRUCTURED_OUTPUT" ]; then echo "::error::Agent skills drift checker did not return a structured verdict." exit 1 fi has_drift=$(printf '%s' "$STRUCTURED_OUTPUT" | jq -r '.hasDrift') if [ "$has_drift" = "true" ]; then echo "::error::Agent skills drift detected. See the agent-skills-drift-check comment on this PR." exit 1 fi if [ "$has_drift" = "false" ]; then echo "No agent skills drift." exit 0 fi echo "::error::Structured verdict present but 'hasDrift' was not a recognizable boolean: $has_drift" exit 1