Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion almanac/architecture/automation/contributor-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ That remediation flow has its own validation boundary. If it applies any fixes,

## Agent Guards

`dangerfile.ts` protects `README.md`, `LICENSE`, `CLAUDE.md`, `assets/**`, `.claude/**`, `.codex/**`, and `.cursor/**` from agent-authored pull request changes [@dangerfile]. It detects agent authorship from the PR author, commit author names and emails, and `Co-authored-by` trailers [@dangerfile]. The Danger workflow runs `npm run danger:ci` on pull requests to `main` after installing dependencies on Node 24 [@danger-workflow] [@package].
`dangerfile.ts` protects `README.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `LICENSE`, `CLAUDE.md`, `docs/**`, `assets/**`, `.claude/**`, `.codex/**`, and `.cursor/**` from agent-authored pull request changes [@dangerfile]. It detects agent authorship from the PR author, commit author names and emails, and `Co-authored-by` trailers [@dangerfile]. The Danger workflow runs `npm run danger:ci` on pull requests to `main` after installing dependencies on Node 24 [@danger-workflow] [@package].

For detected-agent pull requests, Danger fails any changed path matching `PROTECTED_PATHS` and warns when the policy files `dangerfile.ts` or `.github/workflows/danger.yml` change [@dangerfile]. It also enforces inline `agent-guard:off` and `agent-guard:on` regions: invalid marker nesting fails, agent-authored changes inside protected regions fail, and marker changes warn for explicit review [@dangerfile]. The lookup version of this contract belongs in [Protected Paths](../../reference/contributor/protected-paths).
10 changes: 5 additions & 5 deletions almanac/architecture/release/release-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ Rudder's release automation is split between a publishing workflow on `main` and

## Version As Release Input

`package.json` is the only version input for the workflows. The package is currently `@ruddercode/rudder-plugin` at version `0.1.0`, and both workflows turn that version into tag `rudder-plugin-v0.1.0` at runtime [@package-json] [@publish-workflow] [@release-alert]. The release-alert workflow performs the same package-name, version, tag, npm, and GitHub Release checks on pull requests to `main` [@release-alert].
`package.json` is the only version input for the workflows. Both workflows read the manifest version at runtime and turn it into tag `rudder-plugin-v<version>` [@package-json] [@publish-workflow] [@release-alert]. The release-alert workflow performs the same package-name, version, tag, npm, and GitHub Release checks on pull requests to `main` [@release-alert].

Both workflows reject any package name other than `@ruddercode/rudder-plugin` before attempting release work [@publish-workflow] [@release-alert]. This is a release invariant: changing the package name affects plugin marketplace metadata, npm publication, and tag naming, so evaluate it through [Prepare Package Release](../../guides/release/prepare-package-release) and [Rudder Plugin Package](../tooling/plugin-package).

## Publish Job

The publish workflow runs on pushes to `main` and on manual dispatch, with a single `publish-rudder-plugin` concurrency group and `contents: write` plus `id-token: write` permissions [@publish-workflow]. Its first shell step checks whether npmjs.org already has `name@version`, whether the package exists at all, whether the `rudder-plugin-v<version>` tag exists, and whether a GitHub Release exists for that tag [@publish-workflow].
The publish workflow runs on pushes to `main` and on manual dispatch, with a single `publish-rudder-plugin` concurrency group and `contents: write` plus `id-token: write` permissions [@publish-workflow]. Its first shell step checks whether npmjs.org already has `name@version`, whether the `rudder-plugin-v<version>` tag exists, and whether a GitHub Release exists for that tag [@publish-workflow].

Those checks create separate flags for each artifact. A missing npmjs.org version enables npm publishing, a missing package plus missing version marks a bootstrap publish, a missing tag enables tag creation, and a missing GitHub Release enables release creation [@publish-workflow]. When any artifact is missing, the job upgrades npm, installs dependencies with `npm ci`, validates the plugin package, publishes to npmjs.org when needed, pushes the plugin tag when needed, and creates the GitHub Release with generated notes when needed [@publish-workflow].
Those checks create separate flags for each artifact. A missing npmjs.org version enables npm publishing, a missing tag enables tag creation, and a missing GitHub Release enables release creation [@publish-workflow]. When any artifact is missing, the job upgrades npm, installs dependencies with `npm ci`, writes release telemetry defaults into `src/telemetry-build-config.ts`, validates the plugin package with `DO_NOT_TRACK=1`, publishes to npmjs.org when needed with Trusted Publishing, pushes the plugin tag when needed, and creates the GitHub Release with generated notes when needed [@publish-workflow].

The package scripts are part of that path because the publish workflow validates with `npm run check:agent-layout`, `npm run typecheck`, `npm test`, `npm run build`, and `npm pack --dry-run`, while `npm publish` also uses the package lifecycle in `package.json` [@publish-workflow] [@package-json]. The exact scripts are listed in [Package Scripts](../../reference/tooling/package-scripts).
The package scripts are part of that path because the publish workflow validates with `npm run check:agent-layout`, `npm run typecheck`, `npm test`, `npm run build`, and `npm pack --dry-run`, while `npm publish` also uses the package lifecycle in `package.json` [@publish-workflow] [@package-json]. The GitHub Release title is `Rudder v<version>` even though the tag remains `rudder-plugin-v<version>` [@publish-workflow]. The exact scripts are listed in [Package Scripts](../../reference/tooling/package-scripts).

## Release Alert Job

The release-alert workflow runs on pull requests opened, synchronized, or reopened against `main`; it has read permissions for contents plus write permission for pull request comments [@release-alert]. It uses a per-PR `plugin-release-alert-<pr-number>` concurrency group and cancels in-progress runs on newer pushes, so the latest branch state owns the PR warning [@release-alert].

The alert job mirrors the publish checks without publishing. It checks npmjs.org, bootstrap-token need, tag creation, and GitHub Release creation, then sets `will_release=true` when any release artifact would be created after merge [@release-alert]. A GitHub Script step searches for an existing comment containing `<!-- release-alert -->` and updates it, or creates one when missing [@release-alert]. The comment warns when merge would publish the plugin, use the bootstrap token, create the plugin tag, or create a release, and it switches to a no-release message when all plugin artifacts already exist for the version [@release-alert].
The alert job mirrors the publish checks without publishing. It checks npmjs.org, tag creation, and GitHub Release creation, then sets `will_release=true` when any release artifact would be created after merge [@release-alert]. A GitHub Script step searches for an existing comment containing `<!-- release-alert -->` and updates it, or creates one when missing [@release-alert]. The comment warns when merge would publish the plugin, create the plugin tag, or create a release, and it switches to a no-release message when all plugin artifacts already exist for the version [@release-alert].

## Release Model

Expand Down
17 changes: 10 additions & 7 deletions almanac/architecture/runtime/local-state.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
---
title: "Local State"
summary: "Rudder keeps runtime state in a user-scoped home directory that owns the SQLite database, prompt-capture preference, telemetry identity file, and dashboard port defaults."
summary: "Rudder keeps runtime state in a user-scoped home directory that owns the SQLite database, telemetry identity, update-check cache, backups, and dashboard port defaults."
topics: [architecture, runtime, local-state, sqlite, prompt-capture]
sources:
- id: db-client
type: file
path: src/db/client.ts
- id: prompt-control
type: file
path: src/prompt-control.ts
- id: telemetry
type: file
path: src/telemetry.ts
- id: update-script
type: file
path: skills/rudder/scripts/update.mjs
- id: backup-script
type: file
path: skills/rudder/scripts/backup-tests.mjs
- id: gitignore
type: file
path: .gitignore
---

Rudder local state is the small persistent runtime surface that exists outside the source tree. The database client resolves a Rudder home directory from `RUDDER_HOME` or `~/.rudder`, stores the SQLite database at `rudder.db`, opens that database through a process-wide singleton, enables WAL journaling, applies generated Drizzle migrations, and then exposes Drizzle access [@db-client]. The same home directory stores the prompt-capture disable marker and anonymous telemetry identity file, so [Prompt Branch Store](prompt-branch-store), prompt controls, and [Telemetry](telemetry) share one local state root [@prompt-control] [@telemetry]. Runtime artifacts live under the selected Rudder home instead of a repository-local state directory, while the source tree keeps only the code and configuration that derive those paths [@db-client] [@gitignore].
Rudder local state is the small persistent runtime surface that exists outside the source tree. The database client resolves a Rudder home directory from `RUDDER_HOME` or `~/.rudder`, stores the SQLite database at `rudder.db`, opens that database through a process-wide singleton, enables WAL journaling, applies generated Drizzle migrations, and then exposes Drizzle access [@db-client]. The same home directory stores the anonymous telemetry identity file, the update-check cache, and skill-created test-reset backups, so [Prompt Branch Store](prompt-branch-store), [Telemetry](telemetry), and the skill runtime share one local state root [@telemetry] [@update-script] [@backup-script]. Runtime artifacts live under the selected Rudder home instead of a repository-local state directory, while the source tree keeps only the code and configuration that derive those paths [@db-client] [@gitignore].

## State Root

`rudderHome()` is the owner of the local state path. It returns `process.env.RUDDER_HOME` when that value is present, and otherwise joins the operating-system home directory with `.rudder` [@db-client]. `dbPath()` derives the database location by joining that root with `rudder.db`, and `promptCaptureDisabledPath()` derives the persistent capture preference as `<rudderHome()>/prompt-capture-disabled` [@db-client] [@prompt-control].
`rudderHome()` is the owner of the local state path. It returns `process.env.RUDDER_HOME` when that value is present, and otherwise joins the operating-system home directory with `.rudder` [@db-client]. `dbPath()` derives the database location by joining that root with `rudder.db` [@db-client]. The update helper derives `<rudderHome()>/update-state.json`, and the backup helper writes test-reset backups under `<rudderHome()>/backups/` [@update-script] [@backup-script].

The source tree does not carry a repo-local state directory convention. The repository ignore file covers dependencies, build output, generated backups, logs, environment files, coverage, and editor files, but it does not define a `.rudder/` workspace cache [@gitignore]. The runtime code instead creates the selected Rudder home directory directly, so changing the state location is an environment-variable choice rather than a working-tree layout change [@db-client].

Expand All @@ -37,4 +40,4 @@ Migration application is deliberately part of the open flow. `openDb()` derives

## Shared Boundary

Local state currently covers the SQLite database path, the prompt-capture preference marker, the telemetry identity file, and the dashboard port default. Telemetry builds `identity.json` under `rudderHome()`, reads an existing `{ id }` value when present, and writes a generated UUID there on a best-effort basis when it needs a new anonymous installation identity [@telemetry]. The important invariant is that runtime code should derive persistent paths from `rudderHome()` instead of inventing new repository-local locations. That keeps [Telemetry](telemetry), [Prompt Branch Store](prompt-branch-store), prompt controls, and the environment-variable reference aligned around the same state root [@db-client] [@prompt-control].
Local state currently covers the SQLite database path, the telemetry identity file, the update-check cache, skill backup directories, and the dashboard port default. Telemetry builds `identity.json` under `rudderHome()`, reads an existing `{ id }` value when present, and writes a generated UUID there on a best-effort basis when it needs a new anonymous installation identity [@telemetry]. The update helper writes `update-state.json` atomically through a temporary file with mode `0600` after creating the Rudder home with mode `0700` [@update-script]. The important invariant is that runtime code should derive persistent paths from `rudderHome()` instead of inventing new repository-local locations. That keeps [Telemetry](telemetry), [Prompt Branch Store](prompt-branch-store), the update helper, and the environment-variable reference aligned around the same state root [@db-client] [@telemetry] [@update-script].
Loading
Loading