22 KiB
Agent Guidelines
AI-facing guidance for agent tooling when working with this repository.
Critical Constraints (NEVER VIOLATE)
Test Isolation (MANDATORY)
NEVER touch the user's real ~/.ccs/ or ~/.claude/ directories during tests.
- All code accessing CCS paths MUST use
getCcsDir()fromsrc/utils/config-manager.ts - This function respects
CCS_HOMEenv var for test isolation - WRONG:
path.join(os.homedir(), '.ccs', ...) - CORRECT:
path.join(getCcsDir(), ...)
Tests set process.env.CCS_HOME to a temp directory. Code using os.homedir() directly will modify the user's real files.
Core Function
Multi-provider profile and runtime manager for Claude Code, Factory Droid, Codex CLI, and other compatible targets. See README.md for user documentation.
README Preservation
When editing README.md, keep the file concise and funnel detailed usage into
the docs site, but do not remove the ## Community Projects section or the
## Star History section unless the user explicitly asks for those sections to
be deleted. Treat both as protected README content.
When a contributor adds a useful community integration section to README.md,
prefer preserving the attribution in ## Community Projects and moving the
setup substance into a docs page, rather than deleting the contribution.
Outside provider-specific Gemini and Antigravity docs, avoid using ccs gemini
or ccs agy as the primary hero example, default starter route, or generic
workflow example. Prefer ccs, ccs codex, ccs kiro, ccs glm, Droid
examples, or neutral ccs <provider> placeholders when the page is about a
broader topic.
Design Principles (ENFORCE STRICTLY)
Technical Excellence
- YAGNI: No features "just in case"
- KISS: Simple bash/PowerShell/Node.js only
- DRY: One source of truth (config.yaml)
User Experience (EQUALLY IMPORTANT)
- CLI-Complete: All features MUST have CLI interface
- Dashboard-Parity: Configuration features MUST also have Dashboard interface
- Execution is CLI: Running profiles happens via terminal, not dashboard buttons
- UX > Brevity: Error messages and help text prioritize user success over terseness
- Progressive Disclosure: Simple by default, power features accessible but not overwhelming
When Principles Conflict
- UX > YAGNI for user-facing features (if users need it, it's not "just in case")
- KISS applies to BOTH code AND user experience (simple journey, not just simple code)
- DRY applies to BOTH code AND interface patterns (consistent behavior across CLI/Dashboard)
Common Mistakes (AVOID)
| Mistake | Consequence | Correct Action |
|---|---|---|
Running validate without format first |
format:check fails | Run bun run format BEFORE validate |
| Assuming maintainability check is always strict | PR/feature branches run warning mode by default | Use bun run maintainability:check:strict before merge when touching debt-sensitive code |
Using chore: for dev→main PR |
No npm release triggered | Use feat: or fix: prefix |
Committing directly to main or dev |
Bypasses CI/review | Always use PRs |
| Manual version bump or git tag | Conflicts with semantic-release | Let CI handle versioning |
Forgetting --help update |
CLI docs out of sync | Update src/commands/help-command.ts |
| Forgetting docs update | User docs out of sync | Update docs/ and CCS docs submodule |
GitHub Issue Operations (CCS-Specific)
These rules apply when the task is issue triage, backlog cleanup, labels, comments, Projects, or milestones for this repo.
Scope Boundary
- Treat issue triage as a GitHub-only workflow unless the user explicitly asks for implementation.
- Do NOT create a worktree, branch, PR, or run
/fix,/cook, orkai:maintainerjust to tag issues, post follow-up comments, close duplicates, or clean up backlog state. - Escalate into code workflow only when:
- the user explicitly asks to fix/implement an issue, or
- triage proves the same task now requires code changes.
Read Before Mutating
- Always inspect live issue state first with
gh issue view <n> --json ...orgh api. - Never rely on stale memory, screenshots, or issue titles alone.
- Before closing as resolved, cross-check repo evidence in at least one of:
README.mddocs/CHANGELOG.md- relevant source/help handlers
- If the
ghquery would touch Projects fields, verify token scope first. Missingread:projectis a real blocker, not something to hand-wave around.
Labeling Standard
- Every open issue should end triage with:
- one primary type label:
bug,enhancement,question,documentation,duplicate,invalid, orwontfix - one area label:
area:cli-runtimearea:dashboard-uiarea:config-autharea:provider-integrationarea:install-packagingarea:documentationarea:contributor-workflow
- one primary type label:
- Add routing labels only when they materially change handling:
upstream-blockedneeds-reproneeds-splitdocs-gap
- Use release-state labels for shipped work:
pending-releasereleased-devreleased
- Do NOT create or use status labels like
todo,doing,blocked,done. - Do NOT create provider-name labels unless there is a proven long-term need. Provider names belong in titles/issues, not label spam.
Commenting Rules
- Keep issue comments short, technical, and neutral.
- State the decision plainly: close, keep open, retag, needs repro, duplicate, blocked upstream.
- Include exact evidence when relevant: version, doc path, changelog release, canonical issue, upstream link.
- Do NOT reference internal plans, local report files, agent prompts, or private reasoning.
- Post one maintainer follow-up comment per triage pass. If accidental duplicates are created, delete them with
gh api repos/<owner>/<repo>/issues/comments/<id> -X DELETE.
Closure Rules
- Close immediately when:
- the issue is an obvious duplicate and you can point to the canonical issue
- the feature/fix is clearly shipped and documented
- a previously
pending-releaseissue is now clearly past release and no longer needs tracking
- Keep open and retag when:
- upstream dependency still blocks CCS adoption ->
upstream-blocked - latest-release behavior is unclear ->
needs-repro - issue contains multiple independent asks ->
needs-split - feature likely exists but discoverability/docs are weak ->
docs-gap
- upstream dependency still blocks CCS adoption ->
- Do NOT close just because an issue is old, vague, or inconvenient. Close only with evidence.
Projects And Milestones
- Preferred project model for this repo: one project,
CCS Backlog. - Use Projects for workflow state and priority. Use labels for meaning and routing.
- Milestones are for real ship windows only, not generic categorization buckets.
- If
ghtoken lacksread:project, say so explicitly and stop short of pretending Projects data is available. - Active project:
- owner:
kaitranntt - number:
3 - URL:
https://github.com/users/kaitranntt/projects/3
- owner:
- Active project fields:
Status-> use for work state (Todo,In Progress,Done)Priority->P1for bugs,P2default backlog,P3for broadneeds-splitbuckets unless explicitly reprioritizedFollow-up->Ready,Needs repro,Blocked upstream,Needs split,Docs follow-upNext review-> date only for issues that need a follow-up checkpoint
- When triaging an open issue, make sure it exists in
CCS Backlogand the project fields match the routing labels. - Do NOT create a second backlog project unless the user explicitly wants a project split and gives a reason.
- Current automation path:
- workflow file:
.github/workflows/sync-ccs-backlog-project.yml - sync script:
scripts/github/ccs-backlog-sync.mjs - required Actions secret:
CCS_PROJECT_AUTOMATION_TOKEN
- workflow file:
- Automation mapping must stay aligned with labels:
upstream-blocked->Follow-up=Blocked upstreamneeds-repro->Follow-up=Needs reproneeds-split->Follow-up=Needs splitdocs-gap->Follow-up=Docs follow-up- otherwise ->
Follow-up=Ready
New Or Updated Issue Creation
- When creating issues for this repo:
- assign
@kaitranntt - use conventional issue titles:
bug: ...,feat: ...,docs: ... - keep bodies factual and technical
- avoid personal info and internal-only context
- assign
Quality Gates (MANDATORY)
Quality gates MUST pass before pushing. Both projects have identical workflow.
Pre-Commit Sequence (FOLLOW THIS ORDER)
# Main project (from repo root)
bun run format # Step 1: Fix formatting
bun run lint:fix # Step 2: Fix lint issues
bun run validate # Step 3: Full gate (typecheck + lint + format + maintainability + tests)
bun run validate:ci-parity # Step 4: full CI parity gate (build + validate + base branch check)
# UI project (if UI changed)
cd ui
bun run format # Step 1: Fix formatting
bun run lint:fix # Step 2: Fix lint issues
bun run validate # Step 3: Final check (must pass)
WHY THIS ORDER:
validaterunsformat:checkwhich only VERIFIES—won't fix- If format:check fails, you skipped step 1
- CI runs
validateonly (no auto-fix)—local must be clean
What Validate Runs
| Project | Command | Runs |
|---|---|---|
| Main | bun run validate |
typecheck + lint:fix + format:check + maintainability:check + test:all |
| UI | bun run validate |
typecheck + lint:fix + format:check |
ESLint Rules (ALL errors)
| Rule | Level | Notes |
|---|---|---|
@typescript-eslint/no-unused-vars |
error | Ignore _ prefix |
@typescript-eslint/no-explicit-any |
error | Use proper types or unknown |
@typescript-eslint/no-non-null-assertion |
error | No ! assertions |
prefer-const, no-var, eqeqeq |
error | Code quality |
react-hooks/* (UI only) |
recommended | Hooks rules |
react-refresh/* (UI only) |
vite | Fast refresh |
TypeScript Options (strict mode)
| Option | Value | Notes |
|---|---|---|
strict |
true | All strict flags enabled |
noUnusedLocals |
true | No unused variables |
noUnusedParameters |
true | No unused params |
noImplicitReturns |
true | All paths must return |
noFallthroughCasesInSwitch |
true | Explicit case handling |
Automatic Enforcement
prepublishOnly/prepackrunsbuild:all+validate+sync-version.js- CI/CD runs
bun run validateon every PR (maintainability is warning mode on PR events) - husky
pre-commitruns quick lint/type/format checks - husky
pre-pushruns the fullbun run validate:ci-paritygate onmain/dev/hotfix branches - husky
pre-pushruns a faster feature-branch gate (typecheck+lint:fix+format:check+ targeted checks based on changed files) before GitHub CI handles the full matrix
Maintainability Baseline Gate
- Baseline file:
docs/metrics/maintainability-baseline.json - Metric collector/check script:
scripts/maintainability-baseline.js - Branch-aware gate wrapper:
scripts/maintainability-check.js - Enforcement path:
bun run maintainability:check(included inbun run validate) - Gate modes:
strict: protected branches (main,dev,hotfix/*,kai/hotfix-*) and equivalent CI refswarn: pull request CI and non-protected local branches (non-blocking for parallel PR workflow)- override commands:
bun run maintainability:check:strictbun run maintainability:check:warn
- Gated metrics (must not increase vs baseline):
processExitReferenceCountsynchronousFsApiReferenceCount
- Informational metrics (collected but not gated):
largeFileCountOver350Loc
- Baseline update policy:
- Prefer reducing the metric and keeping the baseline unchanged.
- On protected-branch integration (strict mode), if increase is intentional and accepted, run
bun run maintainability:baseline. - Commit both the code change and
docs/metrics/maintainability-baseline.json, and state reason in PR description.
Critical Constraints (NEVER VIOLATE)
- NO EMOJIS in CLI output - Terminal output uses ASCII only: [OK], [!], [X], [i]
- Scope: CCS CLI terminal output (
src/code that prints to stdout/stderr) - Does NOT apply to: PR descriptions, commit messages, documentation, comments, AI conversations
- Scope: CCS CLI terminal output (
- TTY-aware colors - Respect NO_COLOR env var
- Non-invasive - NEVER modify external tool settings (
~/.claude/settings.json) without explicit user request and confirmation (exception:ccs persistcommand) - Cross-platform parity - bash/PowerShell/Node.js must behave identically
- CLI documentation - ALL CLI changes MUST update respective
--helphandler (see table below) - Idempotent - All install operations safe to run multiple times
- Dashboard parity - Configuration features MUST work in both CLI and Dashboard
Help Location Reference
| Command | Help Handler Location |
|---|---|
ccs --help |
src/commands/help-command.ts |
ccs api --help |
src/commands/api-command.ts → showHelp() |
ccs cleanup --help |
src/commands/cleanup-command.ts → printHelp() |
ccs cliproxy --help |
src/commands/cliproxy-command.ts → showHelp() |
ccs config --help |
src/commands/config-command.ts → showHelp() |
ccs copilot --help |
src/commands/copilot-command.ts → handleHelp() |
ccs cursor --help |
src/commands/cursor-command.ts → handleHelp() |
ccs doctor --help |
src/commands/doctor-command.ts → showHelp() |
ccs docker --help |
src/commands/docker/help-subcommand.ts → showHelp() |
ccs migrate --help |
src/commands/migrate-command.ts → printMigrateHelp() |
ccs env --help |
src/commands/env-command.ts → showHelp() |
ccs persist --help |
src/commands/persist-command.ts → showHelp() |
ccs setup --help |
src/commands/setup-command.ts → showHelp() |
Note: lib/ccs and lib/ccs.ps1 are bootstrap wrappers only—they delegate to Node.js and contain no help text.
Documentation Requirements (MANDATORY)
Documentation is a first-class citizen. ALL user-facing changes require docs updates.
Local Documentation (docs/)
Update local docs/ folder for:
- Architecture changes
- Internal API documentation
- Development guides
CCS Docs Submodule (Owner Only)
For @kaitranntt (repository owner): When adding/changing CLI commands or config options, you MUST also update the CCS docs submodule at ~/CloudPersonal/ccs/docs/:
| Change Type | Files to Update |
|---|---|
| New CLI command/flag | reference/cli-commands.mdx |
| New config option | reference/config-schema.mdx |
| Provider feature | providers/<provider>.mdx |
| New feature | features/<feature>.mdx |
Workflow for docs submodule:
cd ~/CloudPersonal/ccs/docs/
git checkout main && git pull
# Make changes
git add -A && git commit -m "docs: <description>"
git push origin main
For external contributors: Document changes in PR description. Owner will sync to CCS docs.
Pre-Commit Docs Checklist
- Respective
--helpupdated (see Help Location Reference table) - Local
docs/updated if architecture changed - CCS docs submodule updated (owner) or PR description includes docs (contributor)
Feature Interface Requirements
| Feature Type | CLI | Dashboard | Example |
|---|---|---|---|
| Profile creation | ✓ | ✓ | ccs auth create, Dashboard "Add Account" |
| Profile switching | ✓ | ✓ | ccs <profile> (execution is CLI-only) |
| API key config | ✓ | ✓ | ccs api create, Dashboard API Profiles |
| Health check | ✓ | ✓ | ccs doctor, Dashboard Live Monitor |
| OAuth auth flow | ✓ | ✓ | Browser opens from CLI or Dashboard |
| Analytics/monitoring | ✗ | ✓ | Dashboard Analytics (visual by nature) |
| WebSearch config | ✓ | ✓ | CLI flags, Dashboard Settings |
| Remote proxy config | ✓ | ✓ | CLI flags, Dashboard Settings |
File Structure
src/ → TypeScript source (main project)
dist/ → Compiled JavaScript (npm package)
lib/ → Native shell scripts (bash, PowerShell)
ui/src/ → React components, hooks, pages
ui/src/components/ui/ → shadcn/ui components
dist/ui/ → Built UI bundle (served by Express)
Key Technical Details
Profile Mechanisms (Priority Order)
- CLIProxy hardcoded: gemini, codex, agy → OAuth-based, zero config
- CLIProxy variants:
config.cliproxysection → user-defined providers - Settings-based:
config.profilessection → GLM, legacy GLMT compatibility, Kimi - Account-based:
profiles.json→ isolated instances viaCLAUDE_CONFIG_DIR
Settings Format (CRITICAL)
All env values MUST be strings (not booleans/objects) to prevent PowerShell crashes.
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.example.com/anthropic",
"ANTHROPIC_AUTH_TOKEN": "your-api-key",
"ANTHROPIC_MODEL": "model-name"
}
}
Shared Data Architecture
Symlinked from ~/.ccs/shared/: commands/, skills/, agents/
Profile-specific: settings.json, sessions/, todolists/, logs/
Windows fallback: Copies if symlinks unavailable
Code Standards
Architecture
lib/ccs,lib/ccs.ps1- Bootstrap scripts (delegate to Node.js via npx)src/*.ts→dist/*.js- Main implementation (TypeScript)
Bash (lib/*.sh)
- bash 3.2+,
set -euo pipefail, quote all vars"$VAR",[[ ]]tests - NO external dependencies
PowerShell (lib/*.ps1)
- PowerShell 5.1+,
$ErrorActionPreference = "Stop" - Native JSON only, no external dependencies
TypeScript (src/*.ts)
- Node.js 14+, Bun 1.0+, TypeScript 5.3, strict mode
child_process.spawn, handle SIGINT/SIGTERM
Terminal Output
- ASCII only: [OK], [!], [X], [i] (NO emojis in CLI output)
- TTY detect before colors, respect NO_COLOR
- Box borders for errors: ╔═╗║╚╝
Conventional Commits (MANDATORY)
ALL commits MUST follow conventional commit format. Non-compliant commits are rejected by husky.
Format
<type>(<scope>): <description>
Types (determines version bump)
| Type | Version Bump | Use For |
|---|---|---|
feat: |
MINOR | New features |
fix: |
PATCH | Bug fixes |
perf: |
PATCH | Performance |
feat!: |
MAJOR | Breaking changes |
docs:, style:, refactor:, test:, chore:, ci:, build: |
None | Non-release |
Examples
# Good
git commit -m "feat(cliproxy): add OAuth token refresh"
git commit -m "fix(doctor): handle missing config gracefully"
# Bad - REJECTED
git commit -m "added new feature"
git commit -m "Fixed bug"
Branching Strategy
Hierarchy
main (production) ← dev (integration) ← feat/* | fix/* | docs/*
↑
└── hotfix/* (critical only, skips dev)
Standard Workflow
git checkout dev && git pull origin dev
git checkout -b feat/my-feature
# ... develop with conventional commits ...
git push -u origin feat/my-feature
gh pr create --base dev --title "feat(scope): description"
# After testing in @dev:
gh pr create --base main --title "feat(release): promote dev to main"
Hotfix Workflow (Production Emergencies Only)
git checkout main && git pull origin main
git checkout -b hotfix/critical-bug
# ... fix ...
gh pr create --base main --title "fix: critical issue"
# Then sync: git checkout dev && git merge main && git push
Rules
- NEVER commit directly to
mainordev - Feature branches from
dev, hotfixes frommain - dev→main PRs MUST use
feat:orfix:(notchore:) - Delete branches after merge
Automated Releases (DO NOT MANUALLY TAG)
Releases are FULLY AUTOMATED via semantic-release. NEVER manually bump versions or create tags.
| Branch | npm Tag | When |
|---|---|---|
main |
@latest |
Merge PR to main |
dev |
@dev |
Push to dev branch |
CI handles: version bump, CHANGELOG.md, git tag, npm publish, GitHub release.
Development
Testing (REQUIRED before PR)
bun run test # All tests
bun run test:npm # npm package tests
bun run test:native # Native install tests
bun run test:unit # Unit tests
Local Development
bun run dev # Build + start config server (http://localhost:3000)
bun run dev:symlink # Symlink global 'ccs' → dev dist/ccs.js (fast iteration)
bun run dev:unlink # Restore original global ccs
./scripts/dev-install.sh # Build, pack, install globally (full install)
rm -rf ~/.ccs # Clean environment
IMPORTANT: Use bun run dev at CCS root for always up-to-date code. Do NOT use ccs config during development as it uses the globally installed version.
Pre-Commit Checklist
Quality (BLOCKERS):
bun run format— formatting fixedbun run validate— all checks passbun run validate:ci-parity— CI parity passed (required before protected-branch pushes; recommended before PRs)cd ui && bun run format && bun run validate— if UI changed- If touching debt-sensitive code, run
bun run maintainability:check:strictbefore opening/merging PR - If strict mode fails and increase is intentional:
bun run maintainability:baselineand commitdocs/metrics/maintainability-baseline.json
Code:
- Conventional commit format (
feat:,fix:, etc.) - Respective
--helpupdated (see Help Location Reference) — if CLI changed - Tests added/updated — if behavior changed
- README.md updated — if user-facing
Documentation:
- CCS docs updated (owner:
~/CloudPersonal/ccs/docs/) — if CLI/config changed - Local
docs/updated — if architecture changed
Standards:
- CLI output ASCII only (NO emojis in terminal output), NO_COLOR respected
- YAGNI/KISS/DRY alignment verified
- No manual version bump or tags
Error Handling Principles
- Validate early, fail fast with clear messages
- Show available options on mistakes
- Never leave broken state