This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
npm install # install dependencies
npm run build # compile TypeScript to dist/
npm run dev # watch mode (rebuild on changes)
npm run type-check # typecheck without emitting
npm run test # run all tests
npx vitest run src/lib/output.test.ts # run a single test file
npm run format # biome lint + format (auto-fix)After building, npm link makes the ol binary available globally.
ESM-only TypeScript CLI using Commander.js. Entry point: src/index.ts creates the program and registers four command modules.
Each file in src/commands/ exports a registerXxxCommand(program) function that defines subcommands with Commander's chaining API. Commands use async action handlers.
- api.ts: Single
apiRequest<T>(path, body)function. All Outline API calls are POST with Bearer auth. Wraps requests in spinner with per-endpoint messages (SPINNER_MESSAGES map). - auth.ts: Config stored at
~/.config/outline-cli/config.json. Token/URL resolution: env var → config file → default. - output.ts:
outputItem()andoutputList()handle three output modes (human/json/ndjson). Commands define ahumanFormatterfunction and anessentialKeysarray for JSON field filtering.formatError/formatErrorJsonaccept either positional(code, message, hints?)or aBaseCliErrorinstance — errors thrown by@doist/cli-corehelpers (e.g. the delegatedchangelogcommand) route through the top-levelparseAsync().catchinsrc/index.ts, which dispatches viaisJsonMode(). - spinner.ts:
withSpinner(opts, fn)wrapper using yocto-spinner. Auto-disables on non-TTY, JSON output, CI,--no-spinnerflag. - markdown.ts: Terminal markdown rendering via marked + marked-terminal.
- Document IDs are resolved from full URLs or slugs via regex extraction in
resolveId(). - Text input for create/update supports
--textinline or--filepath, with auto title extraction from markdown headings. - Delete operations require
--confirmflag.
Vitest with module mocking. Tests are colocated next to the source they cover (foo.ts → foo.test.ts); shared test fixtures live in src/_fixtures/. Common patterns:
- Mock
apiRequestwithvi.mock() - Stub
fetchglobally for API tests - Capture output with
captureConsole(method?)/captureStream(stream?)from@doist/cli-core/testing(auto-restoring spies); readspy.mock.callsfor assertions - Build the command harness with
createTestProgram(register)from@doist/cli-core/testing(appliesexitOverride()), thenprogram.parseAsync() - Auth tests use tmpdir with
process.pidfor filesystem isolation
The file src/lib/skills/content.ts exports SKILL_CONTENT — a comprehensive command reference that gets installed into AI agent skill directories via ol skill install. This is the source of truth that agents use to understand available CLI commands.
Whenever commands, subcommands, flags, or options are added, updated, or removed in src/commands/, the SKILL_CONTENT in src/lib/skills/content.ts must be updated to match.
After updating SKILL_CONTENT:
- Run
npm run build && npm run sync:skillto regenerateskills/outline-cli/SKILL.md(the standalone skill file used bynpx skills add) - Run
ol skill update claude-code(and any other installed agents) to propagate changes to installed skill files
A CI check (npm run check:skill-sync) runs on pull requests and will fail if skills/outline-cli/SKILL.md is out of sync with content.ts.
- Biome: tabs for indentation, auto-sorted imports
- TypeScript strict mode, target ES2022, NodeNext modules
- Avoid
anytypes and forced typecasts - Prefer
forloops over.forEach()