Agent skill

Dashboard

by SethGammon in SethGammon/Citadel

Real-time harness observability dashboard. An agent skill from SethGammon/Citadel.

MITAuto-check passedDevOps & Cloud

Install Dashboard

skills CLI
$ npx skills add SethGammon/Citadel --skill dashboard -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install SethGammon/Citadel dashboard --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/SethGammon/Citadel.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/dashboard .claude/skills/dashboard && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
dashboard
GitHub stars
922
Token cost
~3.6k tokens
SKILL.md length
1,381 words
Files
4
Skills in repo
48
Repo updated
First seen
Licence
MIT

At a glance

Real-time harness observability dashboard. An agent skill from SethGammon/Citadel.

  • Works in 5 steps: RUN DASHBOARD IMPLEMENTATION → COLLECT STATE → FORMAT RELATIVE TIMESTAMPS → …
  • Tasks that involve Observability
  • SKILL.md covers When to Use, Inputs, Protocol and Contextual Gates, plus 2 more sections
  • Calls node, git and npm

What it does

Dashboard is an agent skill from SethGammon/Citadel. Real-time harness observability dashboard. Reads campaigns, fleet sessions, telemetry, and pending queues to present a snapshot of harness state at a glance. Invoked by /dashboard, /do status, or phrases like "what's happening" and "show activity".

Its SKILL.md is about 3.6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files (for example `__benchmarks__/active-campaign.md`, `__benchmarks__/no-planning-dir.md` and `__benchmarks__/vague-status-phrase.md`).

It sits in DevOps & Cloud, covering Observability. The repository describes itself as: The operating layer for Claude Code + OpenAI Codex: persistent project memory, intent routing, safety hooks, cost telemetry, and parallel agent fleets. The licence is MIT.

When your agent uses it

  • Tasks that involve Observability

Example prompts

  • “s happening”
  • “show activity”
  • “/dashboard”

Workflow steps

5 steps, taken from the step headings in SKILL.md.

  1. RUN DASHBOARD IMPLEMENTATION
  2. COLLECT STATE
  3. FORMAT RELATIVE TIMESTAMPS
  4. RENDER DASHBOARD
  5. FRINGE CASE HANDLING

What it can do on your machine

Read from SKILL.md and the folder at commit e41ff1d. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • node
    • git
    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use git and npm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Dashboard loads about 3.6k tokens when it runs. Until then it costs about 65 tokens; SKILL.md has 1,381 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~65
When it runs · the whole SKILL.md, loaded when a task matches
~3.6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from SethGammon/Citadel at commit e41ff1d, republished under its MIT licence (© SethGammon). 1,381 words, ~3,562 tokens.

Download SKILL.mdSave it as .claude/skills/dashboard/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
dashboard
description
Real-time harness observability dashboard. Reads campaigns, fleet sessions, telemetry, and pending queues to present a snapshot of harness state at a glance. Invoked by /dashboard, /do status, or phrases like "what's happening" and "show activity".
license
MIT
user-invocable
true
auto-trigger
false
trigger_keywords
dashboard, what's happening, what's going on, show activity, harness state, show me status
last-updated
2026-03-26

/dashboard — Harness Observability Dashboard

When to Use

  • "What's happening?" / "Status?" / "What's going on?"
  • "Show activity" / "Show me the dashboard"
  • After returning to a project after time away
  • When /do routes "status", "dashboard", "what's happening", "what's going on", "show activity"
  • Directly: /dashboard

Inputs

None required. Works with whatever state exists on disk.

Protocol

Step 0: RUN DASHBOARD IMPLEMENTATION

Run the local dashboard implementation from the project root:

bash
node scripts/dashboard.js

If the package scripts are available, this equivalent command is also valid:

bash
npm run dashboard

The script is read-only. It renders a user-facing control-plane snapshot from .planning/, telemetry, hook config, coordination state, worktrees, and cost data. Use the manual collection protocol below only as a fallback if the script is missing or fails in the current project.

Step 1: COLLECT STATE

Read the following sources. Each is optional — if a file or directory doesn't exist, treat it as empty. Never crash on missing state.

Campaigns:

  • Glob .planning/campaigns/*.md
  • For each file, read the first 40 lines to extract:
    • Status: field
    • Direction: field (truncate to 60 chars)
    • Phase progress (search for Phase N of M or ## Phase headings)
    • Most recent line starting with - [ from the Decision Log
  • If all phases are complete but status is still active, report needs-completion and show: node scripts/campaign.js complete <slug> --archive
  • If a campaign is marked completed but still lives in .planning/campaigns/, report needs-archive and show the same archive command.
  • If prior build/verify phases are complete but the review-package Exit Evidence row is still pending, missing, or points at a missing local package, report a repair before campaign completion: node scripts/package-delivery.js <slug>

Cost Data (two sources, prefer real):

  • Primary: run node scripts/session-tokens.js --today and --all — reads Claude Code's native session JSONL for exact token counts
  • Fallback: read .planning/telemetry/session-costs.jsonl; cost priority real_cost > override_cost > estimated_cost; group by campaign_slug, sum cost/agents/minutes, compute grand total
  • Live session: read .planning/telemetry/cost-tracker-state.json for burn rate
  • Label real data "(real)" and estimates "(est)"

Fleet Sessions:

  • Glob .planning/fleet/session-*.md
  • For each file, read the first 30 lines to extract:
    • status: field
    • wave: or wave number
    • agents: or agent count

Recent Telemetry:

  • Read last 50 lines of .planning/telemetry/hook-timing.jsonl (if it exists)
  • Read last 50 lines of .planning/telemetry/audit.jsonl (if it exists)
  • Merge and sort by timestamp (descending). Take the 10 most recent entries.
  • For each entry: extract ts (or timestamp), hook (or event), and a short description field. Format as relative time.

Recent Hook Activity (separate from general telemetry):

  • Read last 20 lines of .planning/telemetry/hook-timing.jsonl
  • For event: "timing" entries: extract hook, duration_ms, timestamp (relative), and outcome (pass if no matching error in hook-errors.jsonl within 1s; block if a block entry exists)
  • For event: "counter" entries: extract metric name as the "event" column with count context

Hook Overhead (timing percentiles):

  • Read all of .planning/telemetry/hook-timing.jsonl (if it exists)
  • Keep only entries with a numeric duration_ms; group by hook
  • Per hook compute: count, p50, p95, max (nearest-rank percentile over the sorted durations)
  • Sort rows by p95 descending
  • If the file is missing or contains no timed entries, render the one-line note instead

Routine Quota (account-wide 15 runs / 24h cap):

  • Read .planning/telemetry/routine-runs.jsonl (if it exists)
  • Expected JSONL shape, one record per quota-consuming run: {"ts": "<ISO timestamp>", "kind": "RemoteTrigger" | "CronCreate" | "ScheduleWakeup"}
  • Count records with ts inside the last 24 hours; compare against the cap of 15
  • Warn when the count exceeds 12 (hitting the cap pauses every routine on the account; see docs/ROUTINE-QUOTA.md)
  • The harness does not write this file automatically yet — remote-run logging populates it when a routine mechanism is actually used. Local runners (local-watch.js, local-daemon.js, local-schedule.js) never consume quota and must not be counted.

Pending Queues:

  • Count actionable entries in .planning/telemetry/doc-sync-queue.jsonl where status is pending or needs-review (or 0 if missing)
  • Count lines in .planning/telemetry/merge-check-queue.jsonl (or 0 if missing)
  • Count files in .planning/intake/ (or 0 if missing)

Hook Value Data (for HOOKS VALUE section):

  • Read .planning/telemetry/hook-errors.jsonl (if it exists, last 200 lines)
    • Count entries where hook = "protect-files" (blocked file access)
    • Count entries where hook = "external-action-gate" (gated external actions)
    • Count entries where hook = "quality-gate" (quality violations)
  • Read .planning/telemetry/hook-timing.jsonl (if it exists, last 200 lines)
    • Count entries where hook = "circuit-breaker" and metric = "trips"
    • Count total entries from today (entries containing today's ISO date prefix)
  • Read .planning/telemetry/audit.jsonl (if it exists, last 200 lines)
    • Count entries mentioning "circuit-breaker" or "circuit_breaker"

Hook Problem Taxonomy:

  • Read last 100 entries from .planning/telemetry/hook-errors.jsonl.
  • Classify protect-files blocks and hard external-action-gate blocks as safety-block with info severity; they prove protection fired and do not create a repair action by themselves.
  • Classify error and parse-fail actions as hook-failure with high severity; these are actionable.
  • Classify blocked-restricted as restricted-scope-block with high severity; this is actionable.
  • Classify first-encounter and consent-block from external-action-gate as approval-needed with medium severity; this is actionable.
  • If an external-action-gate approval entry has a later matching tool-call entry in audit.jsonl, classify it as resolved-approval with info severity; it should not create a repair action. Treat git push -u and git push as equivalent for the same branch, and allow a small near-simultaneous timestamp skew between hook and tool-call entries.
  • If an unresolved external approval entry is older than 15 minutes, classify it as stale-approval with low severity; it should not create a current repair action.
  • Classify entries older than 24 hours as stale with low severity and do not create a repair action from stale entries.
  • The /telemetry repair action should appear only when actionable entries are present. Safety blocks remain visible in PROBLEMS and HOOKS VALUE.

Health:

  • Count circuit breaker entries from audit.jsonl (from hook value data above)
  • Count total lines in .planning/telemetry/audit.jsonl written today
  • Count entries in hooks array of .claude/hooks-template.json (or .claude/hooks.json if template not present); use 0 if neither exists
  • Read .claude/harness.json (Citadel's shared config path for all runtimes, including Codex) → trust object:
    • sessions_completed, campaigns_completed counters
    • Compute level: novice (sessions < 5), familiar (5-19), trusted (20+ with 2+ campaigns)
    • If trust.override is set, use that and note "(override)"
Show full SKILL.md (419 more words)Show less
Step 2: FORMAT RELATIVE TIMESTAMPS

Convert ISO timestamps: <60s → "just now" | <60min → "{N} min ago" | <24h → "{N} hr ago" | else → "{N} days ago". Display unparseable timestamps as-is.

Step 3: RENDER DASHBOARD

Output verbatim, substituting real values. Always show section headers even when content is "(none active)".

=== Citadel Dashboard ===
As of: {relative timestamp of most recent event, or "now"}

NEXT ACTION
  Command: {exact command}
  Why: {why this is next}
  Confidence: {low | medium | high}
  Repair available: {yes | no}
  Runbook: {docs or skill path}

REPAIR CONSOLE
  {repair|review} | {confidence} | {label}
    command: {exact command}
    why: {short reason}
    runbook: {docs or skill path}

CAMPAIGNS
  {slug}: Phase {N}/{total} — {direction, max 60 chars, ellipsis if truncated}
  Last event: {most recent telemetry entry for this campaign, or "no telemetry"}
  (none active)

COSTS
  This session: ${cost} | {duration} min | ${rate}/min | {messages} msgs | {agents} agents
  Today:        ${today_total} across {today_sessions} sessions
  All time:     ${all_time_total} across {all_time_sessions} sessions ({data_source})

  By campaign:
    {slug}: ${total_cost} across {sessions} sessions ({agents} agents, {minutes} min)
    _unattached: ${total_cost} across {sessions} sessions
  (no cost data recorded yet)

ROUTINE QUOTA
  Runs (last 24h): {N}/15
  WARNING: {N} of 15 routine runs used in the last 24h. Hitting the cap pauses every routine on the account. See docs/ROUTINE-QUOTA.md.
  (remote-run logging populates .planning/telemetry/routine-runs.jsonl - local runners do not consume quota)

HOOKS VALUE
  Circuit breaker: {N} trips (prevented token spirals)
  Quality gate:    {N} violations caught pre-commit
  Protect-files:   {N} blocks (path traversal, secrets)
  External gate:   {N} actions gated
  Total hook fires today: {N}
  (raw facts only -- no inflated savings claims)

FLEET SESSIONS
  {slug}: Wave {N} — {agent count} agents — {status}
  (none active)

RECENT ACTIVITY (last 10 events)
  {relative time} | {hook/event name} | {description}
  (no telemetry recorded yet)

HOOK ACTIVITY (last 10 hook fires)
  {relative time} | {hook name} | {duration_ms}ms | {outcome: pass/block/warn}
  (no hook timing recorded yet — set CITADEL_DEBUG=true in settings.json for verbose output)

HOOK OVERHEAD (sorted by p95 descending)
  hook                        count      p50      p95      max
  {hook name}                   {N}   {N}ms    {N}ms    {N}ms
  (no hook timing data recorded yet)

PROBLEMS
  Actionable: {N} | Safety blocks: {N} | Resolved approvals: {N} | Stale: {N}
  {relative time} | {severity} | {category} | {hook name} | {description}
  (none recorded)

PENDING
  Doc sync:     {N} items queued
  Merge reviews: {N} items queued
  Intake items:  {N} in .planning/intake/

HEALTH
  Circuit breaker trips this session: {N}
  Audit entries today:                {N}
  Hooks installed:                    {N}
  Operator tier:                      {novice | familiar | trusted} ({N} sessions, {N} campaigns)

QUICK COMMANDS
  /do continue    — resume active campaign
  /do rollback    — restore last checkpoint
  /telemetry      — cost breakdown, hook activity, telemetry settings
  /triage prs     — review open PRs
  /pr-watch       — watch PR CI
  /learn          — extract patterns from last completed campaign
Step 4: FRINGE CASE HANDLING

.planning/ missing: All zeros, "(none active)"; add "Run /do setup --express to initialize." harness.json missing or malformed: Show "not configured" for hooks count; do not crash. Malformed campaign file: Skip it; note (N campaign file(s) skipped — malformed). Large telemetry files: Read last 50 lines only. Missing timestamps: Fall back to file modification time; display entry without timestamp if unavailable. All campaigns completed: Note "No active campaigns" at top of CAMPAIGNS section. Completed campaign still active: Show the exact node scripts/campaign.js complete <slug> --archive repair command; suggesting /do continue here is wrong because the campaign is already finished. Campaign ready for review package: Show the exact node scripts/package-delivery.js <slug> repair command before showing campaign completion. All fleet sessions idle: Note "No active fleet sessions" under FLEET SESSIONS. routine-runs.jsonl missing or no runs in window: Show Runs (last 24h): 0/15 plus the one-line population hint; only show the WARNING line when more than 12 runs are counted. Mixed state: Proceed with whatever state exists; note each missing directory inline. Doc-sync backlog: Surface /learn --doc-sync as a repair action with skills/learn/SKILL.md as runbook. Dirty worktree: Surface git status --short as a review action; do not suggest destructive cleanup. Only safety blocks recorded: Show them in PROBLEMS and HOOKS VALUE, but do not surface /telemetry as NEXT ACTION. Actionable hook problem recorded: Surface /telemetry as repair action with skills/telemetry/SKILL.md as runbook.

Contextual Gates

Disclosure: "Displaying harness dashboard. No files modified." Reversibility: green — read-only; no files modified Trust gates:

  • Any: view the full dashboard

Quality Gates

  • Dashboard must render even when all state files are missing
  • Never display raw JSON to the user — always parse and format
  • Relative timestamps required — never show raw ISO strings in output
  • Campaign direction truncated to 60 chars with "..." if longer
  • NEXT ACTION must include command, why, confidence, repair availability, and runbook when known
  • REPAIR CONSOLE must list actionable repairs before raw activity logs
  • Safety blocks must not be treated as urgent repairs unless paired with an actionable hook failure, approval, or restricted-scope block
  • Total output must be skimmable in under 30 seconds

Exit Protocol

/dashboard does not produce a HANDOFF block. It is a read-only observability tool. After displaying the dashboard, wait for the next user command.

© SethGammon, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 3 other files in skills/dashboard of SethGammon/Citadel.

  • SKILL.md
  • __benchmarks__/active-campaign.md
  • __benchmarks__/no-planning-dir.md
  • __benchmarks__/vague-status-phrase.md

Open the folder on GitHubat commit e41ff1d

Compare with similar skills

Dashboard next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Dashboard compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Dashboard this skillSethGammon/Citadel922—~3.6kAutomated safety check: PassMIT
Vercel Optimize Auditvercel-labs/agent-skills32k9 repos~4.3kAutomated safety check: PassNone
Kubeshark Installerkubeshark/kubeshark12k—~3.6kAutomated safety check: NotesApache-2.0
Kubeshark KFL2 Filter Referencekubeshark/kubeshark12k—~3.6kAutomated safety check: PassApache-2.0
KubeSphere ServiceMesh Managerkubesphere/kubesphere17k—~2.4kAutomated safety check: PassCustom licence
Kubernetes Network Root Cause Analysiskubeshark/kubeshark12k—~5.3kAutomated safety check: PassApache-2.0

Similar skills

  • Vercel Optimize Audit

    vercel-labs/agent-skills

    Official

    Runs a metrics-first audit of a deployed Vercel project, gating investigations on real signals to produce ranked, citation-backed cost and performance recommendations.

    32k GitHub starsUsed in 9 repos~4.3k tokens
    DevOps & CloudAuto-check passed
  • Kubeshark Installer

    kubeshark/kubeshark

    Installs and configures Kubeshark on a Kubernetes cluster, choosing between the quick CLI path and a Helm install with custom values.

    12k GitHub stars~3.6k tokensUpdated today
    DevOps & CloudAuto-check: notes
  • Syntax reference for KFL2, the CEL-based display filter language used to search Kubernetes network traffic captured by Kubeshark, loaded before any filter is written.

    12k GitHub stars~3.6k tokensUpdated today
    DevOps & CloudAuto-check passed
  • KubeSphere ServiceMesh Manager

    kubesphere/kubesphere

    Installs, checks and troubleshoots the KubeSphere ServiceMesh extension (Istio, Kiali, Jaeger), including grayscale release, sidecar injection, topology and tracing issues.

    17k GitHub stars~2.4k tokensUpdated 2 mo ago
    DevOps & CloudAuto-check passed
  • Investigates past Kubernetes incidents from Kubeshark traffic snapshots: takes captures, dissects API calls, extracts PCAPs and compares traffic over time.

    12k GitHub stars~5.3k tokensUpdated today
    DevOps & CloudAuto-check passed
  • Caveman Gateway Setup

    JuliusBrussee/caveman

    Routes every LLM call in a repository through the Caveman Cloud gateway in record mode, so requests and costs are measured without changing behavior.

    110k GitHub starsUsed in 1 repo~2.6k tokens
    DevOps & CloudAuto-check: warnings

More from SethGammon/Citadel

All 48 skills in this repo
  • Create Skill

    SethGammon/Citadel

    Creates new skills from the user's repeating patterns. An agent skill from SethGammon/Citadel.

    922 GitHub stars~1.9k tokensUpdated 6 days ago
    Auto-check passed
  • Houseclean

    SethGammon/Citadel

    Cross-drive storage audit and cleanup. An agent skill from SethGammon/Citadel.

    922 GitHub stars~2.2k tokensUpdated 6 days ago
    Auto-check passed
  • Loop

    SethGammon/Citadel

    Bounded foreground repetition for the current session. An agent skill from SethGammon/Citadel.

    922 GitHub stars~1.4k tokensUpdated 6 days ago
    Auto-check passed
  • Triage

    SethGammon/Citadel

    GitHub issue and PR investigator. An agent skill from SethGammon/Citadel.

    922 GitHub stars~2.7k tokensUpdated 6 days ago
    Auto-check passed
  • Watch

    SethGammon/Citadel

    File sentinel that monitors the working directory for changes and marker comments, then auto-triggers appropriate skills.

    922 GitHub stars~2.9k tokensUpdated 6 days ago
    Auto-check passed
  • Archon

    SethGammon/Citadel

    Autonomous multi-session campaign agent. An agent skill from SethGammon/Citadel.

    922 GitHub stars~5.4k tokensUpdated 6 days ago
    Auto-check passed

Categories

Questions about Dashboard

What does Dashboard do?

Real-time harness observability dashboard. An agent skill from SethGammon/Citadel. Dashboard is an agent skill from SethGammon/Citadel. Real-time harness observability dashboard.

When should I use Dashboard?

Dashboard fits situations like: tasks that involve Observability.

How do I install Dashboard in Claude Code?

Run `npx skills add SethGammon/Citadel --skill dashboard -a claude-code`. Or copy the skill folder (skills/dashboard in SethGammon/Citadel) into .claude/skills/dashboard in your project. Claude Code loads it when a task matches its description.

How do I install Dashboard in Codex?

Run `npx skills add SethGammon/Citadel --skill dashboard -a codex`. Or copy the skill folder (skills/dashboard in SethGammon/Citadel) into .agents/skills/dashboard in your project. Codex loads it when a task matches its description.

Can I use Dashboard in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add SethGammon/Citadel --skill dashboard -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/dashboard, .gemini/skills/dashboard, .github/skills/dashboard and .opencode/skills/dashboard in your project.

What does Dashboard need to run?

Going by SKILL.md and its folder, Dashboard needs the command-line tools its instructions call (node, git and npm).

Does Dashboard access the network?

SKILL.md contains no URLs. Its commands use git and npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Dashboard safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Dashboard use?

Dashboard is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Dashboard use?

About 3.6k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Dashboard?

Skills that share tags, products or a category with Dashboard: Vercel Optimize Audit (vercel-labs/agent-skills, 32k stars), Kubeshark Installer (kubeshark/kubeshark, 12k stars), Kubeshark KFL2 Filter Reference (kubeshark/kubeshark, 12k stars) and KubeSphere ServiceMesh Manager (kubesphere/kubesphere, 17k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Dashboard?

SethGammon (a GitHub user) maintains it in SethGammon/Citadel, which has 922 GitHub stars. The repository holds 48 skills in this directory. The repository was last updated on October 1, 2026.

Source: SethGammon/Citadel on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.