Skip to content

scripts/export-archon-core.mjs

Source location: docs/source-files/scripts/export-archon-core.mjs — this page is a rendered mirror; the file is the source of truth.

export-archon-core.mjs
js
import { promises as fs } from 'node:fs'
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const ROOT = path.resolve(__dirname, '..')

const ARCHON_VERSION = readFileSync(
  path.resolve(ROOT, '.archon/VERSION'),
  'utf8',
).trim()

const PLATFORMS = {
  cursor: { prefix: '.cursor', ruleExt: '.mdc' },
  'claude-code': { prefix: '.claude', ruleExt: '.md' },
}

const args = process.argv.slice(2)
const overwrite = args.includes('--overwrite')
const platformFlag = args.find((a) => a.startsWith('--platform='))
const platformName = platformFlag ? platformFlag.split('=')[1] : 'cursor'
const platform = PLATFORMS[platformName]

if (!platform) {
  console.error(
    `[archon-export] Unknown platform: ${platformName}. Available: ${Object.keys(PLATFORMS).join(', ')}`,
  )
  process.exitCode = 1
  process.exit()
}

const positionalArgs = args.filter((a) => !a.startsWith('--'))
const outputArg = positionalArgs[0] ?? 'archon-standalone'
const outputDir = path.isAbsolute(outputArg) ? outputArg : path.resolve(ROOT, outputArg)

const SRC_PREFIX = '.cursor'

const ARCHON_CORE_FILES = [
  '.archon/soul.md',
  '.archon/soul/delivery.md',
  '.archon/soul/review.md',
]

const DOMAIN_LENS_FILES = [
  '.archon/domain-lenses/README.md',
  '.archon/domain-lenses/registry.yaml',
  '.archon/domain-lenses/lenses/dev.md',
  '.archon/domain-lenses/lenses/design.md',
  '.archon/domain-lenses/lenses/platform.md',
  '.archon/domain-lenses/lenses/ecosystem.md',
  '.archon/domain-lenses/lenses/capability.md',
  '.archon/domain-lenses/tools/dev/implementation-path.md',
  '.archon/domain-lenses/tools/dev/blast-radius.md',
  '.archon/domain-lenses/tools/dev/validation-plan.md',
  '.archon/domain-lenses/tools/platform/platform-boundary.md',
  '.archon/domain-lenses/tools/ecosystem/starter-catalog.md',
  '.archon/domain-lenses/tools/ecosystem/evidence-gate.md',
  '.archon/domain-lenses/tools/ecosystem/adoption-path.md',
  '.archon/domain-lenses/tools/capability/need-map.md',
  '.archon/domain-lenses/tools/capability/practice-selector.md',
  '.archon/domain-lenses/tools/capability/adoption-plan.md',
  '.archon/domain-lenses/tools/design/palette-boundary.md',
  '.archon/domain-lenses/tools/design/layout-reference.md',
  '.archon/domain-lenses/tools/design/component-pattern.md',
  '.archon/domain-lenses/tools/design/interaction-state.md',
  '.archon/domain-lenses/tools/design/visual-constraint.md',
  '.archon/domain-lenses/tools/design/critique-audit-loop.md',
  '.archon/domain-lenses/templates/lens.md',
  '.archon/domain-lenses/templates/tool.md',
]

const PLATFORM_FILES = [
  `${SRC_PREFIX}/commands/archon.md`,
  `${SRC_PREFIX}/commands/archon-plan.md`,
  `${SRC_PREFIX}/commands/archon-demand.md`,
  `${SRC_PREFIX}/commands/archon-review.md`,
  `${SRC_PREFIX}/commands/archon-dashboard.md`,
  `${SRC_PREFIX}/agents/archon-reviewer.md`,
  `${SRC_PREFIX}/agents/archon-capture-auditor.md`,
  `${SRC_PREFIX}/rules/archon.mdc`,
  `${SRC_PREFIX}/rules/archon-wake.mdc`,
  `${SRC_PREFIX}/skills/archon-framework/SKILL.md`,
  `${SRC_PREFIX}/skills/archon-git-commit/SKILL.md`,
  `${SRC_PREFIX}/skills/archon-signs/SKILL.md`,
  `${SRC_PREFIX}/skills/blink-dispatch/SKILL.md`,
  `${SRC_PREFIX}/skills/external-agent-patterns/SKILL.md`,
]

const TEMPLATE_FILE_MAP = [
  { source: 'docs/archon/templates/manifest.template.md', target: '.archon/manifest.md' },
  { source: 'docs/archon/templates/drift.template.md', target: '.archon/drift.md' },
  { source: 'docs/archon/templates/debt.template.md', target: '.archon/debt.md' },
  { source: 'docs/archon/templates/memos.template.md', target: '.archon/memos.md' },
  { source: 'docs/archon/templates/decisions.template.md', target: '.archon/decisions.md' },
]

const UNIVERSAL_TOOL_FILES = [
  '.archon/contracts/governance-contract.yaml',
  'scripts/archon-check.py',
  'scripts/archon-check.sh',
  'scripts/archon-run-state.mjs',
  'scripts/archon-claim-verifier.mjs',
]

const DOC_FILE_MAP = [
  { source: 'docs/archon/README.md', target: 'docs/archon/README.md' },
  { source: 'docs/archon/architecture.md', target: 'docs/archon/architecture.md' },
  { source: 'docs/archon/setup.md', target: 'docs/archon/setup.md' },
  { source: 'docs/archon/decisions.md', target: 'docs/archon/decisions.md' },
  { source: '.archon/templates/run.template.md', target: '.archon/templates/run.template.md' },
  { source: '.archon/templates/run-state.schema.json', target: '.archon/templates/run-state.schema.json' },
  { source: '.husky/pre-commit', target: '.husky/pre-commit' },
  { source: '.husky/pre-push', target: '.husky/pre-push' },
  { source: '.cursor/hooks.json', target: '.cursor/hooks.json' },
  { source: '.cursor/hooks/archon-destructive-guard.mjs', target: '.cursor/hooks/archon-destructive-guard.mjs' },
  { source: '.gitattributes', target: '.gitattributes' },
  { source: 'scripts/archon-records.mjs', target: 'scripts/archon-records.mjs' },
  { source: 'scripts/archon-records-fold.mjs', target: 'scripts/archon-records-fold.mjs' },
]

const DOC_ASSET_FILES = [
  'docs/images/archon/readme/01-owner-not-assistant.png',
  'docs/images/archon/readme/02-question-router.png',
  'docs/images/archon/readme/03-mechanism-lanes.png',
  'docs/images/archon/readme/04-delivery-route.png',
  'docs/images/archon/readme/05-domain-tool-theme-palette-case.png',
  'docs/images/archon/architecture/archon-architecture-01-axioms.png',
  'docs/images/archon/architecture/archon-architecture-02-system-map.png',
  'docs/images/archon/architecture/archon-architecture-03-layered-model.png',
  'docs/images/archon/architecture/archon-architecture-04-wake-loop.png',
  'docs/images/archon/architecture/archon-architecture-05-delivery-lifecycle.png',
  'docs/images/archon/architecture/archon-architecture-06-constraint-pyramid.png',
  'docs/images/archon/architecture/archon-architecture-07-evolution-forecast.png',
  'docs/images/archon/architecture/archon-architecture-08-subagent-delegation.png',
  'docs/images/archon/architecture/archon-architecture-09-state-memory.png',
  'docs/images/archon/architecture/archon-architecture-10-extensibility-hygiene.png',
  'docs/images/archon/architecture/archon-architecture-11-records-folder.png',
  'docs/images/archon/architecture/archon-architecture-12-preservation-axis.png',
  'docs/images/archon/architecture/archon-architecture-13-claim-verifier.png',
  'docs/images/archon/architecture/archon-architecture-14-modularity-probe.png',
  'docs/images/archon/setup/01-install-route.png',
  'docs/images/archon/setup/02-two-homes.png',
  'docs/images/archon/setup/03-project-state.png',
  'docs/images/archon/setup/04-mechanical-guards.png',
  'docs/images/archon/setup/05-prereqs.png',
  'docs/images/archon/setup/06-cross-ref.png',
  'docs/images/archon/setup/07-validate-command.png',
  'docs/images/archon/setup/08-pre-commit-gates.png',
  'docs/images/archon/setup/09-run-state-lifecycle.png',
  'docs/images/archon/decisions/01-four-lanes.png',
]

function rewritePlatformPrefix(content) {
  if (platformName === 'cursor') return content
  return content.replaceAll(`${SRC_PREFIX}/`, `${platform.prefix}/`)
}

function rewriteRuleExtension(filePath) {
  if (platform.ruleExt === '.mdc') return filePath
  return filePath.replace(/\.mdc$/, platform.ruleExt)
}

function rewritePlatformTargetPath(targetRelPath) {
  let rewritten = targetRelPath.replace(
    new RegExp(`^\\${SRC_PREFIX}/`),
    `${platform.prefix}/`,
  )
  rewritten = rewriteRuleExtension(rewritten)
  return rewritten
}

function fillManifestPlatform(content) {
  if (platformName === 'cursor') return content
  const p = platform.prefix
  return content
    .replace(/<!-- Cursor \/ Claude Code -->/, platformName === 'claude-code' ? 'Claude Code' : platformName)
    .replace(/<!-- \.cursor \/ \.claude -->/, `\`${p}\``)
    .replace(/<!-- \.cursor\/rules \/ \.claude\/rules -->/, `\`${p}/rules\``)
    .replace(/<!-- \.cursor\/skills \/ \.claude\/skills -->/, `\`${p}/skills\``)
    .replace(/<!-- \.cursor\/agents \/ \.claude\/agents -->/, `\`${p}/agents\``)
    .replace(/<!-- \.cursor\/commands \/ \.claude\/commands -->/, `\`${p}/commands\``)
}

function generateClaudeMd() {
  const p = platform.prefix
  return `# Archon Engineering Governance Framework

This project uses [Archon](https://github.com/) for engineering governance.

## Agent Primer (read first)

Before doing any archon-related work in this project, load the framework primer skill: \`${p}/skills/archon-framework/SKILL.md\`. It explains the three-tier layout, cross-reference convention, decoupling rule, and where to find deeper detail. Load it once per session.

## Boot

At the start of each Archon session, hot-path read only the sections needed for the current route:
1. \`.archon/soul.md\` — Engineering principles (route-scoped cognitive core sections)
2. \`.archon/manifest.md\` — Project overview (current-state sections)

Mode-specific soul extensions load on demand — do NOT load at boot:
- \`.archon/soul/delivery.md\` — loaded by \`/archon-demand\`
- \`.archon/soul/review.md\` — loaded by \`/archon-plan\` and \`/archon-review\`

## Commands

| Command | Description | Definition |
|------|------|------|
| \`/archon\` | **Unified entry**: wake + intent routing (or manually specify plan/demand/review) | \`${p}/commands/archon.md\` |
| \`/archon-plan\` | Planning mode: assess current state, recommend next steps | \`${p}/commands/archon-plan.md\` |
| \`/archon-demand\` | Delivery mode: decision gate → self-directed execute → validation gate → close-out | \`${p}/commands/archon-demand.md\` |
| \`/archon-review\` | Full review mode: independent reviewer audit + knowledge health audit | \`${p}/commands/archon-review.md\` |
| \`/archon-dashboard\` | Launch governance visualization dashboard (if \`.archon/dashboard/\` is present) | \`${p}/commands/archon-dashboard.md\` |

## Core Files

| File | Responsibility |
|------|------|
| \`.archon/soul.md\` | Cognitive core — universal engineering principles, route-scoped hot-path sections |
| \`.archon/soul/delivery.md\` | Delivery-mode extension — loaded by \`/archon-demand\` |
| \`.archon/soul/review.md\` | Review-mode extension — loaded by \`/archon-plan\` and \`/archon-review\` |
| \`.archon/manifest.md\` | Project hot context — tech stack, milestones, acceptance criteria, current state, latest validation |
| \`.archon/drift.md\` | Cognitive drift hot index — delivery complexity, latest rows, archive index, review trigger |
| \`.archon/debt.md\` | Technical debt hot gate index — active ID/severity/deadline/status tracking |
| \`.archon/memos.md\` | Stakeholder memo hot index — compact pointers to decision-level conclusions |

## Reference Documentation

| Document | Purpose |
|----------|---------|
| \`docs/archon/README.md\` | One-page navigation to the rest of the docs |
| \`docs/archon/architecture.md\` | Full system design and rationale |
| \`docs/archon/setup.md\` | Setup steps for new projects (you've already run these if you're reading this) |
`
}

function generatePackageReadme() {
  const p = platform.prefix
  const platformLabel =
    platformName === 'cursor'
      ? 'Cursor'
      : platformName === 'claude-code'
        ? 'Claude Code'
        : platformName
  return `# Archon Standalone Kit (${platformLabel})

**Version ${ARCHON_VERSION}** · Apache-2.0 · See \`docs/archon/CHANGELOG.md\` for release notes.

> Exported from Distilgent's Archon core. For quickly reusing Archon governance capabilities in other projects.

## Target Platform

**${platformLabel}** — Platform-specific files (commands/agents/rules/skills) adapted for \`${p}/\` directory. Core files unified in \`.archon/\`.

## Contents

- Project-agnostic core (\`.archon/\`, same path across platforms):
  - \`.archon/soul.md\` (cognitive core — route-scoped hot-path sections)
  - \`.archon/soul/delivery.md\` (delivery-mode extension — loaded by demand)
  - \`.archon/soul/review.md\` (review-mode extension — loaded by plan and review)
  - \`.archon/domain-lenses/\` (Domain Lens pre-Verdict index and proceed-only lens/tool contracts)
- Platform-specific files (\`${p}/\`):
  - \`${p}/commands/archon*.md\` (unified entry + plan / demand / review / dashboard)
  - \`${p}/agents/archon-*.md\` (reviewer / capture-auditor)
  - \`${p}/rules/archon${platform.ruleExt}\` (decoupling rules) + \`${p}/rules/archon-wake${platform.ruleExt}\` (wake trigger)
  - \`${p}/skills/archon-framework/SKILL.md\` (agent primer — loaded on demand when the agent first touches Archon)
  - \`${p}/skills/archon-git-commit/SKILL.md\` (commit-gate skill — reads Run-State v2 or legacy .archon/run.md before any commit)
  - \`${p}/skills/blink-dispatch/SKILL.md\` (thin-slice subagent dispatch gate — decides skip vs use:<subagent>)
  - \`${p}/skills/external-agent-patterns/SKILL.md\` (external-framework evaluation skill — checks role assumptions before borrowing patterns)
- Project state templates (\`.archon/\`, same path across platforms):
  - \`.archon/manifest.md\`
  - \`.archon/drift.md\`
  - \`.archon/debt.md\`
  - \`.archon/memos.md\`
  - \`.archon/decisions.md\` (project-specific ADR ledger template)
- Portable governance contract + reference checkers:
  - \`.archon/contracts/governance-contract.yaml\`
  - \`scripts/archon-check.py\`
  - \`scripts/archon-check.sh\`
  - \`scripts/archon-run-state.mjs\`
- Bundled documentation (universal):
  - \`docs/archon/README.md\` (one-page navigation)
  - \`docs/archon/architecture.md\` (full system design)
  - \`docs/archon/setup.md\` (integration steps)
  - \`docs/archon/decisions.md\` (framework decision log)
  - \`docs/images/archon/...\` (comic explainer assets referenced by bundled docs)
  - \`.archon/templates/run.template.md\` (legacy ephemeral per-delivery run-state schema)
  - \`.archon/templates/run-state.schema.json\` (Run-State v2 JSON schema)
- Commit hook:
  - \`.husky/pre-commit\` (lifecycle + run-state commit gate)
- Runtime artifacts (created on-demand, NOT shipped with the kit):
  - \`.archon/memos-archive/<year>-Q<N>.md\` (cold archive of full stakeholder memo rationale)
  - \`.archon/drift/archive/<year>-Q<N>.md\` (cold archive of older drift rows)
  - \`.archon/debt/archive/<year>-Q<N>.md\` (cold archive of full debt rationale)
  - \`.archon/manifest/archive/<year>-Q<N>.md\` (cold archive of long latest-review detail)
  - \`.archon/extensions/\` (project-local lifecycle hooks — create per project)
  - \`.archon/dashboard/\` (optional governance visualization — copy from authoring source if you want it)
${platformName === 'claude-code' ? '- Claude Code entry: `CLAUDE.md`\n' : ''}
## Quick Start

1. Copy this directory's contents to the target project root.
2. Have the AI agent read \`${p}/skills/archon-framework/SKILL.md\` first — it's the framework primer.
3. Fill in \`.archon/manifest.md\` per your project (especially §Platform path mappings and §Tech Stack).
4. Register a validation command in your project (lint + typecheck + test).
5. Configure pre-commit lifecycle gate per \`docs/archon/setup.md\`.
6. Run \`/archon-plan\` to verify successful integration.
`
}

async function pathExists(targetPath) {
  try {
    await fs.access(targetPath)
    return true
  } catch {
    return false
  }
}

async function ensureParent(targetPath) {
  await fs.mkdir(path.dirname(targetPath), { recursive: true })
}

async function copyDirect(sourceRelPath, targetRelPath = sourceRelPath) {
  const source = path.resolve(ROOT, sourceRelPath)
  const destination = path.resolve(outputDir, targetRelPath)
  if (!(await pathExists(source))) {
    throw new Error(`Source file not found: ${sourceRelPath}`)
  }
  await ensureParent(destination)
  const content = await fs.readFile(source, 'utf8')
  await fs.writeFile(destination, content, 'utf8')
  return targetRelPath
}

async function copyPlatformFile(sourceRelPath, targetRelPath = sourceRelPath) {
  const source = path.resolve(ROOT, sourceRelPath)
  const destRelPath = rewritePlatformTargetPath(targetRelPath)
  const destination = path.resolve(outputDir, destRelPath)
  if (!(await pathExists(source))) {
    throw new Error(`Source file not found: ${sourceRelPath}`)
  }
  let content = await fs.readFile(source, 'utf8')
  content = rewritePlatformPrefix(content)
  await ensureParent(destination)
  await fs.writeFile(destination, content, 'utf8')
  return destRelPath
}

async function copyTemplateFile(sourceRelPath, targetRelPath) {
  const source = path.resolve(ROOT, sourceRelPath)
  const destination = path.resolve(outputDir, targetRelPath)
  if (!(await pathExists(source))) {
    throw new Error(`Source file not found: ${sourceRelPath}`)
  }
  let content = await fs.readFile(source, 'utf8')
  content = rewritePlatformPrefix(content)
  content = fillManifestPlatform(content)
  await ensureParent(destination)
  await fs.writeFile(destination, content, 'utf8')
  return targetRelPath
}

async function main() {
  const exists = await pathExists(outputDir)
  if (exists && !overwrite) {
    throw new Error(
      `Output directory already exists: ${outputDir}\nUse --overwrite to replace it.`,
    )
  }
  if (exists && overwrite) {
    await fs.rm(outputDir, { recursive: true, force: true })
  }
  await fs.mkdir(outputDir, { recursive: true })

  const exported = []

  for (const file of ARCHON_CORE_FILES) {
    const dest = await copyDirect(file)
    exported.push(dest)
  }

  for (const file of DOMAIN_LENS_FILES) {
    const dest = await copyDirect(file)
    exported.push(dest)
  }

  for (const file of PLATFORM_FILES) {
    const dest = await copyPlatformFile(file)
    exported.push(dest)
  }

  for (const { source, target } of TEMPLATE_FILE_MAP) {
    const dest = await copyTemplateFile(source, target)
    exported.push(dest)
  }

  for (const file of UNIVERSAL_TOOL_FILES) {
    const dest = await copyPlatformFile(file)
    exported.push(dest)
  }

  for (const { source, target } of DOC_FILE_MAP) {
    const dest = await copyPlatformFile(source, target)
    exported.push(dest)
  }

  for (const file of DOC_ASSET_FILES) {
    const dest = await copyDirect(file)
    exported.push(dest)
  }

  if (await pathExists(path.resolve(ROOT, '.gitignore'))) {
    await copyDirect('.gitignore', '.gitignore')
  }

  for (const file of ['LICENSE', 'NOTICE', '.archon/VERSION', 'docs/archon/CHANGELOG.md']) {
    if (await pathExists(path.resolve(ROOT, file))) {
      const dest = await copyDirect(file)
      exported.push(dest)
    }
  }

  if (platformName === 'claude-code') {
    const claudeMdPath = path.resolve(outputDir, 'CLAUDE.md')
    await fs.writeFile(claudeMdPath, generateClaudeMd(), 'utf8')
    exported.push('CLAUDE.md')
  }

  const readme = generatePackageReadme()
  await fs.writeFile(path.resolve(outputDir, 'README.md'), readme, 'utf8')

  console.log(`[archon-export] Platform: ${platformName}`)
  console.log(`[archon-export] Version: ${ARCHON_VERSION}`)
  console.log(`[archon-export] Exported ${exported.length} files to: ${outputDir}`)
}

main().catch((error) => {
  console.error(`[archon-export] ${error.message}`)
  process.exitCode = 1
})

Released under the Apache-2.0 License.