Skip to content

Contributing

Follow these guidelines when contributing to Sencai.

Before making changes, read these — they are the current, living references (not this page’s prose):

  • .claude/AGENTS.md — agent roles and autonomy boundaries
  • .claude/context/ — architecture, glossary, onboarding, audit patterns, code review checklist
  • PHASE-5-PLAN.md / PHASE-6-PLAN.md (repo root) — the current phase plans (PHASE-5 is gate-overridden and in active local execution, PHASE-6 is prep-stage); PHASE-2-PLAN.md, PHASE-3-PLAN.md, and PHASE-4-PLAN.md have all been archived under ai-context-staging/phase-2/, phase-3/, and phase-4/ respectively, now that those phases are implementation-complete

Sencai’s monorepo is a polyrepo: each service (sencai.space, api-manager, cloud-connector, sencai-web, and roughly 30 others) is its own independent Git repository with its own remote — there is no single root repository tying them together.

There is no main branch in any of these repos. Every active repository has exactly one long-lived branch, dev, and that is what CI builds from. A handful of older repos (ai-context-staging, auth-service-consumer, bootstrap, graphql-gateway) still carry a leftover master branch from before the dev-only convention was settled, but none of them use it as an integration target — dev is the branch that matters everywhere.

There is also no evidence of feature-branch workflows in any repo’s history — real practice is Conventional Commits landing directly on dev:

Terminal window
git checkout dev
git pull origin dev
# ...make changes...
git add .
git commit -m "fix(security): account-limit-guard invite bypass"
git push origin dev

A main-based Git Flow model with feature/* branches, PR review, and tag-triggered releases does not exist in this codebase today. If you’ve seen that model described elsewhere (including in .claude/skills/release.md — see note below), treat it as aspirational, not current practice.

Use Conventional Commits, as a single-line message:

Terminal window
git commit -m "feat(billing): add overview endpoint"

Per the root CLAUDE.md: one sentence, no trailing period, no commit body/footer conventions like Closes #42 are in use.

Hard rule — no exceptions: commits must never include Co-Authored-By, Signed-off-by, or any mention of Claude/AI, in the message or in code/comments. This is enforced project-wide. (Note: a small number of early historical commits predate this rule being enforced — do not use them as a precedent.)

TypeDescription
featNew feature
fixBug fix
docsDocumentation
choreBuild, deps, tooling
refactorRefactoring (no behavior change)
testAdd/modify tests
ciCI/CD pipeline changes
perfPerformance improvement

There is currently no PR-based review process in day-to-day use: no PULL_REQUEST_TEMPLATE.md, no CODEOWNERS file, and no pull_request-triggered CI workflow exist across the repos for the primary lint/test/build gate (ci.yml) — it runs on push to dev only. If a PR-and-review workflow is introduced in the future, this section will be updated to match; until then, treat any PR/branch/squash-merge process described here or elsewhere as aspirational, not current practice.

Every change must update the affected service’s CHANGELOG under ## [Unreleased].

Use Keep a Changelog:

## [Unreleased]
### Added
- New feature
### Changed
- Changed behavior
### Fixed
- Fixed bug
### Removed
- Removed endpoint
## [Unreleased]
### Added
- GET /api/billing/overview endpoint
- Monthly cost aggregation
### Fixed
- Keycloak sync loop issue

Migration discipline differs by service — see .claude/skills/db-migration.md for the full per-service breakdown. The two most common patterns:

  • Strapi (sencai.space) — Knex migrations under database/migrations/. Never modify or delete an existing migration file; always add a new one. Migrations run automatically on Strapi startup. For content-type field changes, schema.json updates usually generate the migration automatically.
  • Cloud Connector (cloud-connector) — TypeORM entity sync, not file-based migrations. Schema changes are made directly to entity definitions under src/database/entities/; in dev, TypeORM’s synchronize: true applies the schema, and production changes go through typeorm migration:generate. This is a different discipline from Strapi’s — don’t assume Knex-style migration files exist here.

Never delete or modify existing Knex migrations, regardless of service.

Terminal window
# Backend
cd sencai.space && npm test
# Frontend
cd sencai.space-frontend && npm test
# Microservices
cd api-manager && npm test

CI runs on every push to dev (not on pull requests — there is no PR trigger for the primary pipeline). The core ci.yml gate typically runs:

  1. Lint — ESLint + Prettier
  2. Type check — TypeScript
  3. Tests — Jest/Vitest
  4. Build — Production build

Two additional gates run independently of ci.yml, on a schedule as well as on push:

  • Dependency Audit (dependency-audit.yml) — npm audit (blocking on high/critical), runs on push to dev and nightly via a 0 4 * * * cron.
  • Secret scanning (gitleaks.yml) — scans for committed secrets; several repos run this via the gacts/gitleaks action (a license-gate-free wrapper around the same OSS gitleaks scanner, adopted after gitleaks/gitleaks-action@v2 started requiring a paid license for org repos).

All gates must pass before changes are considered mergeable/deployable in practice, even without a formal PR review step enforcing it.

If adding features or services:

service-name/
├── README.md ← add documentation
├── CLAUDE.md ← context for Claude Code
├── CHANGELOG.md ← Keep a Changelog format
└── .env.example ← all ENV variables
  • README.md — description, tech stack, how to run
  • CLAUDE.md — context for Claude Code
  • CHANGELOG.md — Keep a Changelog format
  • .env.example — all environment variables
  • Dockerfile — containerization
  • .dockerignore — exclude build files

Exception: purely config-only directories with no application code of their own — auth-service/, git-service/, sencai-mq/, k8s-agent/ — don’t need a Dockerfile/.dockerignore/.env.example, since their runtime image comes from an upstream project (Keycloak, Gitea, RabbitMQ) rather than being built here. infra-gcp/ (CDKTF infrastructure-as-code) is likewise exempt from the Dockerfile/.dockerignore requirement, since it’s not a running service.

Move [Unreleased] in each service’s CHANGELOG.md to a dated version section when cutting a release:

## [1.2.0] - 2026-04-20
### Added
- Billing overview
### Fixed
- Keycloak sync

Then bump the version in package.json:

{
"version": "1.2.0"
}

That part of the workflow is real and current practice.

What is not current practice: there is no main branch to merge into, no git tag v1.2.0 step, and no tag-triggered release pipeline. The only image tagging scheme actually observed in the repos is dev-latest — the Docker image is rebuilt and pushed to ghcr.io under that single tag on every push to dev. Versioned image tags (ghcr.io/...:v1.2.0) and GitHub Releases are not part of the current pipeline.

.claude/skills/release.md currently documents the same unsupported devmain → tagged-release flow described above as removed from this page. That skill file should eventually be corrected to match the dev-only, dev-latest-tag reality, but updating it is out of scope for this content fix.

  • Never commit .env — use .env.example
  • Never commit unencrypted secrets — API keys, tokens, passwords
  • Validate input — always
  • Use parameterized queries — prevent SQL injection
  • Configure CORS/CSRF — properly
IssueCauseSolution
CI “push” failedLint errorRun npm run lint:fix locally before pushing
Tests don’t passMissing fixtureCheck test setup
Dependency Audit failsHigh/critical npm audit findingFix the dependency or document in the service’s audit allowlist with notes + expiry
CHANGELOG missingForgot to update [Unreleased]Update CHANGELOG.md before considering the change done

For onboarding and architecture questions, start with .claude/AGENTS.md and .claude/context/onboarding.md rather than generic community channels — this is an internal platform without public GitHub Issues/Discussions or a community chat set up for contribution questions.

See each service’s .github/workflows/ for its actual CI/CD gates.