This file provides coding conventions and quick-reference for AI assistants working on this codebase.
pnpm build # Build all packages (tsc --build)
pnpm test # Run all tests (vitest run)
pnpm lint # Lint (oxlint)
pnpm typecheck # Type-check only (tsc --build --dry)
make -C native # Build native C helper (requires musl-tools)- Strict mode: All strict flags enabled, plus
noUncheckedIndexedAccess,exactOptionalPropertyTypes,verbatimModuleSyntax - ESM only: Use
import typefor type-only imports. No CommonJS. - Target: ES2024. Module resolution: Node16.
- No
any: Useunknownand narrow with type guards. - No
==: Always use===(enforced by oxlinteqeqeq: error). - No
console.log: Use structured logging or remove before commit (oxlintno-console: warn). - Zero lint diagnostics: All lint errors and warnings must be fixed before considering work complete. The GitHub CI workflow runs
pnpm lintand will fail the build on any lint diagnostic. Never leave lint warnings as "pre-existing" or "to be ignored" -- fix them immediately.
- Source in
packages/<name>/src/ - Tests co-located as
*.test.tsnext to source files - Each package has
src/index.tsbarrel file exporting public API - Types in
types.tsper module directory
- Files: kebab-case (
tool-registry.ts,rate-limit.ts) - Types/Interfaces: PascalCase (
CapabilityEnforcer,SandboxPolicy) - Functions/Variables: camelCase (
validateAuthToken,findHelper) - Constants: camelCase or UPPER_SNAKE for true constants
- Error classes:
<Domain>Error(AuthError,PermissionError,VaultError)
- Dependency injection: Pass dependencies via constructor options or function parameters. No global state.
- Fail-closed: Default to denying access. Security checks must explicitly allow.
- Custom error classes: Each domain has its own error class extending
Error. - No database: All runtime state is in-memory. Only the vault persists to disk.
Use Conventional Commits format:
type(scope): description
# Types: feat, fix, test, docs, refactor, chore, ci
# Scopes: core, cli, sandbox, vault, native, gateway, webchat, security, skills, tools, ci
Examples:
feat(core): add streaming support to agent loopfix(sandbox): handle ENOENT for missing helper binarytest(security): add crypto key rotation test
- Create
packages/core/src/tools/builtin/<name>.ts - Implement the
ToolHandlerinterface (frompackages/core/src/tools/types.ts) - Declare
requiredCapabilitieson the handler - Register in
packages/core/src/tools/builtin/index.ts - Add capability grants to
skills/builtin/manifest.json - Write co-located test
<name>.test.ts
- Create
packages/<name>/withpackage.json,tsconfig.json,src/index.ts - Add to
pnpm-workspace.yaml(already usespackages/*glob) - Add project reference in root
tsconfig.json - Package
tsconfig.jsonshould extend../../tsconfig.build.json
- Tool calls MUST pass through
CapabilityEnforcerbefore execution - Sandbox execution MUST NOT be optional or bypassable by tool code
- Vault file permissions MUST be 0o600
- Auth tokens MUST use timing-safe comparison (
timingSafeEqual) - Skill manifests MUST have valid Ed25519 signatures before loading
- Rate limiting MUST NOT be removable without code changes
PR_SET_NO_NEW_PRIVSMUST be set before any sandbox enforcement
| Package | Key Exports |
|---|---|
@safeclaw/vault |
Vault, encrypt, decrypt, deriveKeyFromPassphrase, KeyringProvider |
@safeclaw/sandbox |
Sandbox, detectKernelCapabilities, findHelper |
@safeclaw/core |
Agent, CapabilityRegistry, CapabilityEnforcer, ToolOrchestrator, SimpleToolRegistry, AuditLog, Session, SessionManager, CopilotClient, SkillLoader, SkillInstaller |
@safeclaw/gateway |
Gateway, validateAuthToken, RateLimiter |
@safeclaw/webchat |
WebChatAdapter |
@safeclaw/cli |
CliAdapter, bootstrapAgent, CLI commands |