Coding Conventions
This page documents the coding standards and patterns used across all services in The Shift Platform.
TypeScript
- Target:
ESNext - Module:
nodenext - Strict mode: Always enabled
- Runtime: Bun (with
@types/bunfor type checking) - No CommonJS: All packages use
"type": "module"inpackage.json
Formatting and Linting
The platform uses Biome for both formatting and linting:
- Quotes: Double quotes (
") - Indentation: 2 spaces
- Rules: Biome recommended rules
- Config:
biome.jsonat the platform root; submodules have their own identical copy
Run before committing:
bun run check # Lint + format check
bun run format # Auto-format
Testing
- Framework:
bun:test - File naming:
*.test.tsalongside the source file they test - Location: Tests live next to the code they test, not in a separate directory
bun run test # All tests
cd yellowpages && bun test # Single service
CLI Conventions
All CLI commands use Commander.js and follow these patterns:
Global Flags
Every command supports:
--json-- Output structured JSON for agent consumption--quiet-- Suppress all stdout, exit code only
Command Pattern
command
.argument("<id>", "Service ID or name")
.option("--json", "Output as JSON")
.option("--quiet", "Suppress output")
.action(async (id, options) => {
// 1. Validate input
// 2. requireRoot() — ensure store directory exists
// 3. Load data
// 4. Operate
// 5. output(result, options) — handles json/quiet/human modes
});
Exit Codes
Use semantic exit codes from @shift/platform-core/exit-codes:
| Code | Constant | Meaning |
|---|---|---|
0 | EXIT_SUCCESS | Operation completed |
1 | EXIT_ERROR | General error |
2 | EXIT_USER_ERROR | Invalid input |
3 | EXIT_NOT_INITIALIZED | Store directory missing |
4 | EXIT_NOT_FOUND | Resource not found |
5 | EXIT_CONNECTION | Server unreachable |
API Conventions
All HTTP APIs use Hono and follow these patterns:
Factory Pattern
Each service exports a createApp() function that returns a Hono app:
import { Hono } from "hono";
import { errorHandler } from "@shift/platform-core/api/error-handler";
import { healthRoute } from "@shift/platform-core/api/health";
export function createApp() {
const app = new Hono();
app.use("*", errorHandler());
app.route("/healthz", healthRoute("my-service"));
// ... routes
return app;
}
Response Envelope
All responses use the standard envelope from @shift/platform-core/api/response:
import { ok, err } from "@shift/platform-core/api/response";
// Success
return c.json(ok(data));
// { "success": true, "data": { ... } }
// Error
return c.json(err("NOT_FOUND", "Service not found"), 404);
// { "success": false, "error": { "code": "NOT_FOUND", "message": "Service not found" } }
Error Handling
Use error helpers from @shift/platform-core/api/error-handler:
import { badRequest, notFound, conflict } from "@shift/platform-core/api/error-handler";
if (!name) throw badRequest("Name is required");
if (!service) throw notFound("Service not found");
if (existing) throw conflict("Service already exists");
ID Conventions
- Generation:
nanoid(8)for all application-level IDs - Resolution: All commands and endpoints accept either an ID or a human-readable name
- Convex bridging: App uses
id, Convex uses_id, and every table has asidfield (shift ID) indexed for fast lookup
Storage Conventions
Services define store interfaces in packages/shared/src/repository.ts and provide implementations for each backend:
packages/shared/src/
repository.ts # Store interface
store/
file.ts # File-based implementation
convex.ts # Convex implementation
factory.ts # createStore() factory based on SHIFT_STORAGE
The factory reads SHIFT_STORAGE from the environment and returns the appropriate implementation.
Output Triple
Every CLI command supports three output modes via the output() helper from @shift/platform-core/output:
- Human (default): Chalk-colored, formatted for terminals
- JSON (
--json): Structured output for agent consumption - Quiet (
--quiet): No stdout, exit codes only