Contributing to Caracal
June 1, 2026 · View on GitHub
Prerequisites
| Tool | Version |
|---|---|
| Node.js | 24+ |
| pnpm | 11.1.1 |
| Docker + Compose v2 | 24+ |
| Go | 1.26+ |
| Python | 3.14+ |
| Bun | latest |
<os>∈linux·darwin·windows<arch>∈x64·arm64
Modes
| Dev | RC | Stable | |
|---|---|---|---|
| Purpose | Development builds | rc builds | Released production versions |
| Version | 2026.05.27-dev.sha<sha> | 2026.05.27-rc.1 / 0.1.3-rc.1 | 2026.05.27 / 0.1.3 |
| Container images | localhost/caracal-{svc}:2026.05.27-dev.sha<sha> | ghcr.io/garudex-labs/caracal-{svc}:v2026.05.27-rc.1 | ghcr.io/garudex-labs/caracal-{svc}:v2026.05.27 |
Setup
git clone https://github.com/Garudex-Labs/caracal.git && cd caracal
pnpm install
pnpm caracal up # Build and start the full stack
# Essential Commands
pnpm caracal --help # Show runtime shell help and available lifecycle commands
pnpm caracal status # Check health status of all services
pnpm caracal down [--help] # Stop the stack
pnpm caracal purge # Remove stack, volumes, logs, cache, and installed data
Drop the `pnpm` prefix
pnpm link --global # Install global symlink
pnpm unlink --global caracal # Remove global symlink
Console
pnpm caracal console # Human-facing product management
Standalone execution
pnpm caracal run -- <command> reads validated runtime config from platform environment variables or an explicit runtime profile, exchanges the configured application credentials with STS, injects only the configured scoped resource-token environment variables into the child process, and executes without a shell. The stack does not create zones, applications, client secrets, or runtime profiles. Create a managed application with credential type token, copy the one-time client secret from the create result, and store the local secret and credential manifest under the OS Caracal config directory.
Run example workloads from their example directory:
cd examples/ResearchAgent
cp env.example .env
$EDITOR .env
. .env
pnpm caracal run -- node agent.mjs
The .env file contains only the zone and application identifiers. Local authentication still comes from the auto-detected app client secret at ${XDG_CONFIG_HOME:-$HOME/.config}/caracal/runtime/<zone-id>/<application-id>/client-secret, and resource injection comes from the sibling credentials.json manifest.
Control API (optional)
The Console is the primary human product-management surface. The control service is an optional OAuth-protected HTTP API for approved external clients that need to drive Caracal programmatically.
Clients authenticate by exchanging the Control key credentials for a token whose audience matches CONTROL_AUDIENCE, which defaults to caracal-control. Create the key from the Console Control menu; Caracal generates client_secret and shows it once in the create result. Store it, then drive the enabled Control API from the workflow or client that will use it in production.
Tests
pnpm test # full suite (ts + go + py)
pnpm run test:typescript | test:go | test:python
scripts/testCi.sh mirrors .github/workflows/test.yml locally:
scripts/testCi.sh # full suite (ts + go + py + docs)
scripts/testCi.sh --smoke | --go | --py | --ts
Submitting Changes
- Create a branch from
mainand keep changes focused. - Keep the scope minimal (few files/components, small commits).
- Run a quick local sanity check:
pnpm caracal uppnpm caracal statuspnpm caracal consolepnpm caracal down
- Ensure tests pass:
pnpm testscripts/testCi.sh --smoke(post-commit parity)scripts/testCi.sh(daily-check parity)
- Commit with a clear message and open a PR.
Releases
Release artifacts share one CalVer: vYYYY.MM.DD (.N for same-day re-cuts). Only .github/MAINTAINERS can run release workflows. Stable releases require release-approval from a different maintainer.
Create dev builds
Use dev builds only for development:
pnpm --dir apps/runtime build:release # stamp dev + build local images + bun compile (all targets)
pnpm --dir apps/console build:release # stamp dev + bun compile (all targets)
BIN="$(pwd)/apps/runtime/dist/caracal-<os>-<arch>" # absolute path; survives cd
CONSOLE="$(pwd)/apps/console/dist/caracal-console-<os>-<arch>" # Console binary; same OS/arch matrix
pnpm caracal down # Stop dev before testing
"$BIN" --version # → caracal 2026.05.27-dev.sha<sha> [dev (sha <sha>)]
"$CONSOLE" --version # → caracal-console 2026.05.27-dev.sha<sha> [dev (sha <sha>)]
(cd /tmp && "$BIN" up && "$BIN" status && "$CONSOLE" && "$BIN" down)
build:release stamps dev binaries and local localhost/caracal-{svc}:<base>-dev.sha<sha> images. Do not use dev builds downstream.
Release flow
Use the same flow for rc and stable: plan, dry-run, publish, validate. rc proves the exact artifacts downstream; stable promotes the approved release.
| Step | rc | stable |
|---|---|---|
| Prepare | scripts/release.sh rc prepare --base-version 2026.05.27 --suffix rc.1 | scripts/release.sh stable --dry-run |
| Review | Commit the generated manifest and metadata. | Review the stable diff and generated version. |
| Dry-run | scripts/release.sh rc dry-run --base-version 2026.05.27 --suffix rc.1 --local for local simulation; remote dry-run requires the rc commit on the selected ref. | scripts/release.sh stable --dry-run |
| Publish | Tag and push v2026.05.27-rc.1. | scripts/release.sh stable |
| Validate | postReleaseValidation.yml runs after release. | postReleaseValidation.yml gates stable promotion. |
# rc
scripts/release.sh rc prepare --base-version 2026.05.27 --suffix rc.1
git add -A && git commit -m "rc: v2026.05.27-rc.1"
scripts/release.sh rc dry-run --base-version 2026.05.27 --suffix rc.1 --local
git tag -a v2026.05.27-rc.1 -m v2026.05.27-rc.1
git push origin HEAD && git push origin v2026.05.27-rc.1
# stable
scripts/release.sh stable --dry-run
scripts/release.sh stable
Remote rc dry-runs dispatch release.yml without publishing. They only read the default branch or the exact release tag ref, and the working tree must be clean unless --allow-dirty is used deliberately.
Post-release validation
postReleaseValidation.yml checks registries, archives, installers, containers, and provenance. npm, PyPI, binary, and installer checks cover Ubuntu, macOS, and Windows.
Reproduce one area locally:
CARACAL_RELEASE=v2026.05.27-rc.1 FINDINGS_DIR=/tmp/findings \
bash scripts/postRelease/validateRegistryMetadata.sh
Package publishing
pnpm release:plan --since v2026.05.14
pnpm release:stamp:check
gh workflow run publishNpm.yml -f package=changed -f dryRun=true -f runner=ubuntu-24.04
gh workflow run publishNpm.yml -f package=changed -f runner=ubuntu-24.04
gh workflow run publishPypi.yml -f package=changed -f dryRun=true -f runner=ubuntu-24.04
gh workflow run publishPypi.yml -f package=changed -f runner=ubuntu-24.04
Protected workflows are the normal path for npm and PyPI. They read release.config.json, ignore examples/**, publish changed packages, include exact-pin dependents, preflight Ubuntu/macOS/Windows, and publish once from the selected runner. Use baseRef to override the diff base and package=all only for deliberate full publishes. Local stable publishing requires approval and CARACAL_ALLOW_LOCAL_STABLE_PUBLISH=1.
Published artifacts
npm: @caracalai/{core,oauth,admin,identity,revocation,sdk,
transport-mcp,transport-a2a,
mcp-express,mcp-fastmcp,tokenstate-postgres,revocation-redis}
pypi: caracalai-{core,oauth,identity,revocation,sdk,transport-mcp,mcp-fastmcp,revocation-redis}
ghcr: ghcr.io/garudex-labs/caracal-{api,sts,gateway,audit,coordinator,redis}
Rollback
Never delete a published tag. Roll forward with a new CalVer tag. The floating vYYYY.MM image tag moves with the new cut; pinned v<calver> tags are immutable.
Security
Do not file public issues for vulnerabilities. See SECURITY.md.
License
Apache-2.0. By contributing you agree your contribution is licensed under the same terms (LICENSE).