Automated assistants working in this repository should follow the conventions below before generating or editing content.
jammin (always lowercase) is JAM development tooling for creating, building, deploying, and testing multi-service projects. The project is part of the larger jammin suite which includes:
- jammin cli: Command-line tool for JAM development (this repository's primary focus)
- jammin studio: Future Electron app/VS Code extension for GUI-based development
- jammin inspect: Future web app for inspecting deployed JAM services and networks
- Always spell
jamminin lowercase, even at sentence starts, headings, or product names such asjammin cli,jammin studio, andjammin inspect. - Preserve existing casing for other product names (e.g.,
typeberry,Polkajam,JAMNP).
- Files: kebab-case (enforced by Biome:
build-command.ts,get-service-configs.ts) - Types/Interfaces: PascalCase (
ServiceConfig,DockerError,ProjectConfig) - Functions/Variables: camelCase (
buildService,getJamFiles,projectRoot) - Constants: SCREAMING_SNAKE_CASE for config objects (
SDK_CONFIGS,TARGETS) - Classes: PascalCase, prefer static methods over instances when appropriate
- Prefer concise, task-focused prose with short paragraphs.
- Align terminology with the documentation set in
docs/src; when in doubt, referencedocs/src/bootstrap/jammin-suite.mdfor the canonical wording of suite components. - Update
docs/src/SUMMARY.mdwhenever new pages are added so the mdBook navigation stays accurate. - Use direct, plain language that reads like an experienced (non-native) open source developer explaining the work. Avoid marketing fluff or overly formal sentences; keep the tone practical and grounded.
This is a monorepo using Bun workspaces:
- Root package
@fluffylabs/jamminserves as the main package and build coordinator. bin/cli/contains the CLI implementation (@fluffylabs/jammin-cli)- Commands are organized in
bin/cli/src/commands/using Commander.js - CLI uses
@clack/promptsfor interactive user experiences
bun install # Install all dependencies
bun run build # Build all workspace packages
bun run cli # Run CLI locally during development
bun run bin/cli/index.ts # Alternative way to run CLIbun run qa # Run all quality checks (CI mode - fails on issues)
bun run qa-fix # Fix quality issues automatically
bun run format # Format code with Biome
bun run lint # Lint and fix with Biomebun test # Run all tests (uses Bun's built-in test runner)
bun test bin/cli/src/commands/create-command.test.ts # Run specific test file
bun test --watch # Run tests in watch modeHeads-up for SDK changes. The
@fluffylabs/jammin-sdkpackage is published frompackages/jammin-sdk/dist/, and CLI tests import it via the package name. After editing files underpackages/jammin-sdk/, runbun run buildbeforebun testso test imports see the new symbols. CI runsbun run buildbeforebun testautomatically; the manual step is only needed locally.
- Line width: 120 characters
- Indent: 2 spaces
- Line ending: LF
- Quote style: Double quotes (
"string") - Array types: Shorthand syntax (
string[]notArray<string>) - Block statements: Always use blocks (no single-line if statements)
- Unused imports: Auto-removed (configured in Biome)
- File naming: kebab-case only (enforced)
Run bun run qa before committing to catch all issues.
- Strict mode: Enabled with all strict flags
- Module system: Preserve (bundler mode) with
.tsextensions in imports - Target: ESNext with ESNext libs
- Type safety: Avoid
any, prefer explicit types orunknown - Unused vars: Linted by Biome (errors on unused locals/params/imports)
- Type imports: Use
import type { ... }for type-only imports when possible
// 1. Node built-ins (node: prefix)
import { mkdir } from "node:fs/promises";
import { join, resolve } from "node:path";
// 2. External dependencies
import * as p from "@clack/prompts";
import { Command } from "commander";
// 3. Internal imports (types first, then code)
import type { ServiceConfig } from "../../types/config";
import { getServiceConfigs } from "../../utils/get-service-configs";
import { SDK_CONFIGS } from "../../utils/sdk-configs";Biome will auto-organize imports when you run bun run format.
// Custom errors should extend Error with additional context
export class DockerError extends Error {
constructor(
message: string,
public output: string, // Additional context
) {
super(message);
}
}
// Throw errors with descriptive messages
if (exitCode !== 0) {
throw new DockerError(
`Build failed for service '${service.name}' with exit code ${exitCode}`,
combinedOutput
);
}
// Use type guards for validation
export function validate(name: string) {
if (!name || name.trim().length === 0) {
return new InvalidArgumentError("Project name is required");
}
// ... more validation
return trimmed;
}// Use JSDoc for public APIs
/**
* Build a single service using Docker
*/
export async function buildService(service: ServiceConfig, projectRoot: string): Promise<string>
// Use inline TODO comments with author tag
// TODO: [AuthorName] Description of what needs to be done
// Keep inline comments concise and explain "why" not "what"
const dockerArgs = ["run", "--rm", "-v", `${servicePath}:/app`, sdk.image, ...sdk.build.split(" ")];Each command is in a separate file (bin/cli/src/commands/*-command.ts) and exports a Commander Command object. Commands should support both interactive mode (using clack prompts) and non-interactive mode (using command-line arguments).
When adding new commands:
- Create
bin/cli/src/commands/your-command.ts - Export a Commander
Commandobject - Support both interactive and non-interactive modes
- Use
@clack/promptsfor spinners, progress, and user input - Register command in
bin/cli/index.ts - Add tests in
bin/cli/src/commands/your-command.test.tsusing Bun's test runner
Documentation is in docs/ using mdBook. When adding new pages, update docs/src/SUMMARY.md for navigation. See docs/src/bootstrap/jammin-suite.md for the feature roadmap.
This project uses Bun as the primary runtime and toolchain. Always prefer Bun-native APIs over Node.js or third-party alternatives.
- Use
bun <file>instead ofnode <file>orts-node <file> - Use
bun testinstead ofjestorvitest - Use
bun installinstead ofnpm installoryarn installorpnpm install - Bun automatically loads .env, so don't use dotenv
Bun.filefor file operations instead ofnode:fsreadFile/writeFile when possibleBun.spawn()for running shell commands instead ofchild_processbun:sqlitefor SQLite instead ofbetter-sqlite3- Built-in
WebSocketinstead ofwspackage
import { test, expect } from "bun:test";
test("description", () => {
expect(value).toBe(expected);
});Consult this file at the start of every AI-assisted session to ensure the repository stays stylistically consistent.