Documentation Index
Fetch the complete documentation index at: https://docs.ccs.kaitran.ca/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Headless mode enables CCS to run in non-interactive environments:
- CI/CD Pipelines - GitHub Actions, GitLab CI, Jenkins
- Automated Scripts - Cron jobs, batch processing
- Server-Side Tasks - Background workers, scheduled analysis
- No Browser Required - 7-day session tokens eliminate OAuth flow
How It Works
Session Persistence
When you authenticate via browser, CCS:
- Obtains OAuth token (expires in ~1 hour)
- Stores refresh token (expires in 7 days)
- Creates session file (
~/.ccs/cliproxy/sessions.json)
- Automatically refreshes tokens 5min before expiry
Result: Once authenticated locally, CI/CD can run for 7 days without re-auth.
Headless Delegation Mode
ccs -p "Your prompt here"
This mode:
- Skips interactive prompts - Returns error if auth needed
- Uses default profile - Or specify with first arg:
ccs codex -p "prompt"
- Outputs to stdout - JSON-parsable responses
- Exits with code - 0 = success, non-zero = failure
Prerequisites
- CCS installed on CI runner
- Initial authentication done (see Step 1)
- Session files accessible to CI environment
Authenticate Locally First
You cannot authenticate directly in CI - OAuth requires browser.On your local machine:This creates session files in ~/.ccs/cliproxy/:
sessions.json - Session metadata
gemini-{account}.json - OAuth tokens
Session expiry: 7 days from last token refresh. Copy Session Files to CI
Option A: GitHub Actions SecretsBase64-encode session files:# On local machine
tar -czf ccs-sessions.tar.gz -C ~/.ccs/cliproxy sessions.json gemini-*.json
base64 ccs-sessions.tar.gz > ccs-sessions.b64
Add to GitHub secrets:
- Go to repo Settings → Secrets → Actions
- Create secret
CCS_SESSIONS with contents of ccs-sessions.b64
Option B: GitLab CI Variables# Add as file-type CI/CD variable
cat ccs-sessions.tar.gz | base64
Settings → CI/CD → Variables → Add variable:
- Key:
CCS_SESSIONS
- Type: File
- Value: (paste base64 content)
Option C: Self-Hosted RunnerCopy directly to runner home:scp -r ~/.ccs/cliproxy runner-host:~/.ccs/
Restore Sessions in CI
GitHub Actions:- name: Setup CCS Sessions
run: |
mkdir -p ~/.ccs/cliproxy
echo "${{ secrets.CCS_SESSIONS }}" | base64 -d | tar -xzf - -C ~/.ccs/cliproxy
GitLab CI:before_script:
- mkdir -p ~/.ccs/cliproxy
- base64 -d $CCS_SESSIONS | tar -xzf - -C ~/.ccs/cliproxy
Docker:COPY ccs-sessions.tar.gz /tmp/
RUN mkdir -p ~/.ccs/cliproxy && \
tar -xzf /tmp/ccs-sessions.tar.gz -C ~/.ccs/cliproxy && \
rm /tmp/ccs-sessions.tar.gz
Use Headless Mode in Pipeline
GitHub Actions Example:name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install CCS
run: npm install -g @kaitranntt/ccs@latest
- name: Setup Sessions
run: |
mkdir -p ~/.ccs/cliproxy
echo "${{ secrets.CCS_SESSIONS }}" | base64 -d | tar -xzf - -C ~/.ccs/cliproxy
- name: Run AI Review
run: |
ccs codex -p "Review the changes in this PR and suggest improvements" > review.txt
- name: Post Comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const review = fs.readFileSync('review.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: review
});
GitLab CI Example:review:
stage: test
image: node:20
before_script:
- npm install -g @kaitranntt/ccs@latest
- mkdir -p ~/.ccs/cliproxy
- base64 -d $CCS_SESSIONS | tar -xzf - -C ~/.ccs/cliproxy
script:
- ccs codex -p "Analyze code quality and suggest refactorings" | tee review.txt
artifacts:
paths:
- review.txt
Handle Session Expiry
Sessions expire after 7 days. Options:Option A: Scheduled Re-AuthenticationCreate GitHub Action that runs weekly:name: Refresh CCS Sessions
on:
schedule:
- cron: '0 0 * * 0' # Every Sunday
workflow_dispatch: # Manual trigger
jobs:
refresh:
runs-on: self-hosted # Must have browser
steps:
- name: Re-authenticate
run: |
ccs codex --auth # Opens browser on self-hosted runner
- name: Archive Sessions
run: |
cd ~/.ccs/cliproxy
tar -czf ccs-sessions.tar.gz sessions.json gemini-*.json
base64 ccs-sessions.tar.gz
- name: Update Secret
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh secret set CCS_SESSIONS < ccs-sessions.tar.gz
Option B: Check and Exit Gracefully#!/bin/bash
ccs codex -p "Test prompt" || {
echo "[!] CCS session expired. Please re-authenticate locally and update CI secrets."
exit 1
}
Option C: Remote Proxy (Recommended)Use Remote Proxy to centralize auth on server. Configure Environment Variables
Control behavior via env vars:env:
CCS_DEBUG: "0" # Disable debug logs in CI
CCS_SKIP_PREFLIGHT: "1" # Skip API key validation
CCS_WEBSEARCH_SKIP: "1" # Disable WebSearch hook
CCS_PROXY_FALLBACK_ENABLED: "0" # Fail fast if proxy down
DISABLE_TELEMETRY: "1" # Disable telemetry
DISABLE_ERROR_REPORTING: "1" # Disable error reporting
Security tip: Never log CCS_PROXY_AUTH_TOKEN in CI output. Parse Responses (Advanced)
Headless mode outputs raw AI response. Parse for CI:# Extract JSON from response
ccs codex -p "Analyze this code and return JSON: {score: number, issues: string[]}" | \
jq -r '.score'
# Fail pipeline if score below threshold
SCORE=$(ccs qwen -p "Rate code quality 1-10" | grep -oE '[0-9]+' | head -1)
if [ "$SCORE" -lt 7 ]; then
echo "[X] Code quality score $SCORE below threshold"
exit 1
fi
Example: Extract action itemsccs codex -p "List action items from meeting notes in MEETING.md" | \
grep -E '^\s*[-*]' > action-items.txt
Complete CI/CD Examples
GitHub Actions: Automated Documentation
name: Generate Docs
on:
push:
branches: [main]
paths:
- 'src/**'
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install CCS
run: npm install -g @kaitranntt/ccs@latest
- name: Setup Sessions
run: |
mkdir -p ~/.ccs/cliproxy
echo "${{ secrets.CCS_SESSIONS }}" | base64 -d | tar -xzf - -C ~/.ccs/cliproxy
- name: Generate API Docs
run: |
ccs codex -p "Generate API documentation from src/ directory in Markdown format" > docs/api.md
- name: Commit Docs
run: |
git config user.name "AI Docs Bot"
git config user.email "bot@example.com"
git add docs/api.md
git commit -m "docs: update API documentation [skip ci]" || exit 0
git push
GitLab CI: Code Quality Gate
stages:
- test
- review
quality-check:
stage: test
image: node:20
before_script:
- npm install -g @kaitranntt/ccs@latest
- mkdir -p ~/.ccs/cliproxy
- base64 -d $CCS_SESSIONS | tar -xzf - -C ~/.ccs/cliproxy
script:
- |
ccs qwen -p "Analyze code in src/ and rate quality 1-10. Output only the number." > score.txt
SCORE=$(cat score.txt | grep -oE '[0-9]+' | head -1)
echo "Code quality score: $SCORE/10"
if [ "$SCORE" -lt 7 ]; then
echo "Quality gate failed: score below 7"
exit 1
fi
only:
- merge_requests
Jenkins: Nightly Analysis
pipeline {
agent any
triggers {
cron('H 2 * * *') // 2 AM daily
}
environment {
CCS_DEBUG = '0'
CCS_SKIP_PREFLIGHT = '1'
}
stages {
stage('Setup') {
steps {
sh 'npm install -g @kaitranntt/ccs@latest'
sh 'mkdir -p ~/.ccs/cliproxy'
withCredentials([file(credentialsId: 'ccs-sessions', variable: 'SESSIONS_FILE')]) {
sh 'tar -xzf $SESSIONS_FILE -C ~/.ccs/cliproxy'
}
}
}
stage('Analyze') {
steps {
sh '''
ccs codex -p "Analyze codebase for security vulnerabilities and performance issues" > report.md
'''
}
}
stage('Publish') {
steps {
archiveArtifacts artifacts: 'report.md'
emailext(
subject: "Nightly Code Analysis Report",
body: readFile('report.md'),
to: 'dev-team@example.com'
)
}
}
}
}
Environment Variables Reference
| Variable | Default | Purpose |
|---|
CCS_DEBUG | 0 | Enable verbose logging |
CCS_SKIP_PREFLIGHT | 0 | Skip API key validation |
CCS_WEBSEARCH_SKIP | 0 | Disable WebSearch hook |
CCS_PROXY_FALLBACK_ENABLED | 1 | Fallback to local proxy |
CCS_UNIFIED_CONFIG | 1 | Use unified config mode |
CCS_MIGRATE | 0 | Trigger auto-migration |
DISABLE_TELEMETRY | unset | Disable Claude telemetry |
DISABLE_ERROR_REPORTING | unset | Disable error reporting |
DISABLE_BUG_COMMAND | unset | Disable bug reporting |
Troubleshooting
Authentication Required
Symptom: [X] Auth error: No valid session found
Causes:
- Sessions not restored correctly
- Session files expired (>7 days)
- Wrong provider in headless command
Solutions:
# Verify session files exist
ls -la ~/.ccs/cliproxy/sessions.json
# Check session age
stat -c %y ~/.ccs/cliproxy/sessions.json
# Re-authenticate locally and update CI secrets
Token Refresh Failed
Symptom: [X] Network error: UND_ERR_SOCKET
Causes:
- Firewall blocking OAuth endpoints
- Proxy configuration issues
- Network timeout
Solutions:
# Increase timeout
export CCS_PROXY_TIMEOUT=5000
# Check network access
curl -I https://auth.openai.com
Session File Permissions
Symptom: [X] Config error: EACCES
Cause: Session files not readable by CI user
Solution:
chmod 600 ~/.ccs/cliproxy/sessions.json
chmod 600 ~/.ccs/cliproxy/*.json
Prompt Too Long
Symptom: Command line argument limit exceeded
Solution: Use file redirection:
# Instead of:
ccs codex -p "$(cat large-file.txt)"
# Use:
ccs codex -p "Analyze the content of large-file.txt" < large-file.txt
Security Best Practices
Protect Session Files
- Encrypt in transit: Use secrets/variables, not environment variables
- Rotate regularly: Re-authenticate every 7 days maximum
- Scope access: Limit CI job permissions to necessary secrets
- Audit logs: Monitor secret access in GitHub/GitLab audit logs
Minimize Token Exposure
# ❌ BAD: Token in logs
- run: echo "Token: ${{ secrets.CCS_SESSIONS }}"
# ✅ GOOD: Silent extraction
- run: echo "${{ secrets.CCS_SESSIONS }}" | base64 -d | tar -xzf - -C ~/.ccs/cliproxy
Use Self-Hosted Runners
For sensitive repos, use self-hosted runners:
- Sessions stay on your infrastructure
- No need to upload to GitHub secrets
- Easier re-authentication workflow
Next Steps
Remote Proxy
Centralize auth on server, avoid session expiry issues
Token Management
Deep dive into session persistence and refresh logic