Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

HOANGSA

Context engineering for coding agents — Claude Code, Codex, Cowork.

License: MITClaude CodeBuilt with Rust

🇻🇳 Hoàng Sa, Trường Sa là của Việt Nam 🇻🇳

🇨🇳 中文 · 西沙群岛和南沙群岛属于越南。🇻🇳
🇺🇸 English · Hoàng Sa (Paracel Islands) and Trường Sa (Spratly Islands) belong to Vietnam. 🇻🇳
🇯🇵 日本語 · ホアンサ(パラセル)諸島とチュオンサ(スプラトリー)諸島はベトナムの領土です。🇻🇳
🇪🇸 Español · Las islas Paracel y las islas Spratly pertenecen a Vietnam. 🇻🇳
🇷🇺 Русский · Острова Хоангша и Чыонгша принадлежат Вьетнаму. 🇻🇳
🇫🇷 Français · Les îles Paracels et les îles Spratleys appartiennent au Vietnam. 🇻🇳
🇰🇷 한국어 · 호앙사 군도와 쯔엉사 군도는 베트남의 영토입니다. 🇻🇳


The problem

An agent's output degrades as its context window fills. Ask for a feature and you get good code for the first file, plausible code for the fifth, and by the tenth it has forgotten a type it defined itself. Bigger context windows push the cliff back; they don't remove it.

The usual answers — "be more specific", "break it into steps" — are advice. HOANGSA is structure.

The idea

Split the work into tasks. Give each task its own fresh context window holding only what it needs: the files it may touch, the behaviour it must implement, the command that proves it worked. The orchestrator never writes code — it dispatches, checks, and assembles.

Everything else follows from that:

  • A task needs a spec precise enough to execute from, so there is a design phase that produces one.
  • A worker with no history needs its rules and context handed to it, so prompts are assembled by a CLI, not improvised by an agent.
  • A claim of "done" from a fresh worker is unverifiable, so every deliverable has a command that must pass.

That last one is load-bearing. Prompt text is a suggestion an agent can talk itself out of; a failing exit code is not. Wherever this repo says a rule matters, there is a hoangsa-cli subcommand that enforces it.


The pipeline

brainstorm → menu → prepare → cook → taste → plate → ship
idea specs plan build verify commit push
PhaseProducesEnforced by
brainstormBRAINSTORM.md — options, trade-offs, risk seeds, open questionsstatused open questions
menuDESIGN-SPEC.md + TEST-SPEC.mdvalidate spec, validate tests
prepareplan.json — task DAG with per-task files, behaviour, acceptancevalidate plan, dag check
cookcode, one atomic commit per taskper-task acceptance, validate scope
tasteverdict per taskacceptance re-run, spec-coverage review
plateconventional commit
shippush / PR after reviewreview gates

Each phase is a contract, not a script: mission, deliverables, hard gates. The path between them is the agent's choice; the gates are not.

What the gates actually check

To make it concrete:

  • validate spec — a code spec must carry ## Behavior / Logic (per requirement: trigger, steps, error paths) and a ## Risk Sweep covering eight fixed classes, including concurrency & TOCTOU. Each class is either applies, with concrete handling, or N/A with a reason. An open question with no RESOLVED / DEFERRED status fails the gate — so a question cannot reach the plan without having been put to you.
  • validate plan — every implementation task carries a non-empty behavior, copied from the spec. The worker gets it as a contract: a step it drops or quietly replaces is a failure even when the tests pass.
  • validate scope — a task's commit is checked against the files the plan gave it. Touching an undeclared file is an error, not a note.

Install

curl -fsSL https://github.com/pirumu/hoangsa/releases/latest/download/install.sh | sh

Installs four binaries into ~/.hoangsa/bin/, registers the memory MCP server, and writes the Claude Code hooks. Then, inside your agent:

/hoangsa:init # detect the codebase, set preferences
/hoangsa:menu # design your first task
Platforms, flags, building from source, uninstall

Supported platforms

TripleStatusNotes
darwin-arm64Apple Silicon
linux-x64glibc distros
linux-arm64glibc distros
linux-* musl / AlpineONNX Runtime links glibc — build from source
Windowsuse WSL2

Needs curl or wget, tar, and sha256sum / shasum. No Node, Python, or Docker.

Installer flags

Pass after sh -s --:

FlagEffect
--globalinstall for this user (default)
--localinstall for the current project only (./.claude/)
--no-embedwrite a sticky no-embed marker — no model download, and no project can enable semantic retrieval
--dry-runprint actions without writing
VariableDefaultPurpose
HOANGSA_VERSIONlatestrelease tag to install
HOANGSA_INSTALL_DIR~/.hoangsaroot for binaries and cache
HOANGSA_NO_PATH_EDIT1 skips the shell rc edit
CLAUDE_CONFIG_DIRauto-detectedpin a Claude profile (~/.claude, ~/.zclaude, …)

From source

git clone https://github.com/pirumu/hoangsa.git &&cd hoangsa
scripts/install-local.sh --global

Flags: --global / --local, --dry-run, --skip-build, --no-embed, --embed. The no-embed marker is sticky — a later install without the flag keeps it; pass --embed to clear it deliberately.

PATH

The installer appends a managed block to ~/.zshrc or ~/.bashrc. If that was skipped, add it yourself:

echo'export PATH="$HOME/.hoangsa/bin:$PATH"'>>~/.zshrc &&source~/.zshrc

Update and uninstall

hoangsa-cli update --check # current vs latest; exits 10 if newer
hoangsa-cli update # fetch and install it
hoangsa-cli uninstall --global --dry-run # list what would go
hoangsa-cli uninstall --global # keeps memory + model cache
hoangsa-cli uninstall --global --purge # deletes ~/.hoangsa entirely

scripts/uninstall.sh does the same job from a checkout, for when the binary is missing or will not run.

Other harnesses

HarnessCommandNotes
Claude Codenothing — the installer does it
Codex CLI / Desktophoangsa-cli install --global --harness codexthen run /hooks once in Codex to approve them
Cowork / Desktophoangsa-cli install --harness coworkrestart the app; hooks don't apply inside the VM
Plugin only/plugin marketplace add unknown-studio-dev/hoangsacommands + agents, no binaries

--harness is recorded in .hoangsa/config.json so model routing knows which runtime it is resolving for. On Codex, profile tiers become reasoning effort — Codex has no per-subagent model knob — and the session model is left alone.


Commands

Pipeline

CommandDoes
/hoangsa:brainstormexplore a vague idea → BRAINSTORM.md
/hoangsa:menuinterview → DESIGN-SPEC.md + TEST-SPEC.md
/hoangsa:preparespecs → executable task DAG (plan.json)
/hoangsa:cookexecute wave by wave, fresh context per task
/hoangsa:tasterun acceptance, judge test quality, verify UI
/hoangsa:qcspec → test cases → execute, every verdict backed by evidence
/hoangsa:platestage + conventional commit message
/hoangsa:shipcode + security review, then push or PR
/hoangsa:fixhotfix — cross-layer root cause, minimal change

Utility

CommandDoes
/hoangsa:initdetect the codebase, configure preferences
/hoangsa:checksession progress and pending tasks
/hoangsa:audit9-dimension codebase scan
/hoangsa:researchcodebase + external research → RESEARCH.md
/hoangsa:servetwo-way sync with a task manager
/hoangsa:ruleproject enforcement rules
/hoangsa:addonframework-specific worker-rule addons
/hoangsa:indexrebuild the code-intelligence graph
/hoangsa:updateupgrade HOANGSA
/hoangsa:helplist everything

Memory

hoangsa-memory is a local MCP server giving the agent persistent memory and code-graph awareness. Nothing leaves your machine.

Three surfaces — plain markdown you can read and edit:

FileHolds
MEMORY.mdproject facts and invariants
LESSONS.mdaction-triggered advice (when X → do Y)
USER.mdyour cross-project workflow preferences

A code graph — symbols, callers, callees, imports — behind memory_impact (blast radius before you edit), memory_symbol_context, and memory_detect_changes (did this diff touch only what it claimed?).

Recall fuses local sources with Reciprocal Rank Fusion — symbol lookup, BM25, graph fan-out (depth 1 from the symbol seeds), and all three markdown surfaces. The conversation archive is deliberately not in default recall; query it explicitly with memory_archive_search.

Semantic retrieval — opt-in

[vector_store] enabled defaults to false. The embedder is the heaviest thing here: a 465 MB model cache plus a resident ONNX session whose CPU arena grows to 150–300 MB. Lexical, symbol, and graph retrieval cover most queries at no idle cost, so you turn it on when you decide you want it — per project, in <memory root>/config.toml:

[vector_store]
enabled = true

Then warm the cache once with hoangsa-memory prefetch-embed. A global ~/.hoangsa/no-embed marker overrides this to off everywhere.

ONNX's thread pool is capped at half your cores (max 4). Override with HOANGSA_ONNX_THREADS; 0 restores the runtime default.

LLM reranking — opt-in

Every stage above ranks on form: term overlap, identifier equality, graph edges, rank position. None of them reads a chunk and asks whether it answers the question, so a hit that leads on a literal string match can outrank the one that actually explains the thing.

[rerank]
enabled = truecandidates = 24# fused results shown to the modeltimeout_secs = 20# command = ["claude", "-p"] # default: claude, then codex

It drives whatever harness CLI is already on your PATH — no API key. Two guarantees, because recall sits on the hot path:

  • Fail-open — missing binary, timeout, non-zero exit, or prose instead of JSON all return the fused order unchanged.
  • Reordering only — the model cannot add, drop, or duplicate a result. Anything it doesn't mention keeps its fused rank at the back.

Configuration

.hoangsa/config.json, managed by /hoangsa:init or hoangsa-cli pref set.

Top-level keys: profile, harness, model_overrides, preferences, codebase, task_manager.

Preferences

KeyValuesMeaning
lang / spec_langen, vilanguage for output / for specs
interaction_levelquick, detailedhow much the orchestrator asks
review_stylestrict, balanced, light, whole_documentreview thoroughness
workflow_profilefull, balanced, minimalpreset for the six quality keys below
quality_gateboolreview pass after each task
simplify_passboolcleanup pass after each task
test_runsinthow many times to repeat the suite
research_mode / context_modefull, inline / full, selectiveresearch depth / context packing
memory_strictboolrequire memory consultation before edits
auto_taste / auto_plate / auto_serveboolauto-chain to the next phase

workflow_profile is a quality preset. It is not the top-level profile, which routes models — different key, different vocabulary.

Model routing

profile picks a model per role. An unknown name falls back to balanced.

Rolequalitybalancedbudgetminimal
researcheropussonnethaikuhaiku
designeropusopussonnetsonnet
planneropussonnethaikuhaiku
orchestratoropusopushaikusonnet
workeropussonnethaikuhaiku
revieweropussonnethaikuhaiku
testersonnethaikuhaikuhaiku
committersonnethaikuhaikuhaiku
simplifyopussonnethaikuhaiku

minimal is budget with the orchestrator kept on sonnet — the one seat where the cheap tier usually costs more in rework than it saves, which makes minimal slightly more expensive than budget despite the name.

fable (Claude Fable 5, ~2× opus) belongs to no profile. Route it per role:

{ "model_overrides": { "designer": "fable" } }

On Codex the tier is not a model id — Codex scales by reasoning effort, so fable/opus → high, sonnet → medium, haiku → low, and the session model is left untouched.


The binaries

BinaryRole
hoangsa-cliorchestrator — slash commands, gates, rule engine, hooks, prompt assembly
hoangsa-memorymemory + code intelligence — index, query, impact, archive
hoangsa-memory-mcpthe MCP server your agent talks to (spawned for you)
hspoutput compressor — trims cargo/npm/git/curl noise before the model reads it, 60–90% on the worst offenders. See its README.

Per-project state lives in .hoangsa/; memory in .hoangsa/memory/ or ~/.hoangsa/memory/projects/<slug>/.


Troubleshooting

SymptomFix
command not found: hoangsa-cliPATH not updated in this shell — source ~/.zshrc or open a new terminal
MCP tools missing in Claude CodeCLAUDE_CONFIG_DIR mismatch — set it explicitly before installing
A hoangsa-memory process using a lot of CPUit is embedding. [vector_store] enabled = false (the default) stops it; HOANGSA_ONNX_THREADS caps it. Identify it with ps -o pid,ppid,%cpu,command -p <pid> — a PPID of 1 means a hook spawned it detached
vector_store failed to startdelete ~/.hoangsa/cache/fastembed/, then hoangsa-memory prefetch-embed
validate spec fails on an existing spec0.6.0 requires ## Behavior / Logic and ## Risk Sweep on code specs. Add them, or set category: ops / content in the frontmatter
musl libc detected on Alpinerelease tarballs are glibc-only — build from source
Installer stalls under curl | shstdin is piped; pass flags explicitly and set HOANGSA_NO_PATH_EDIT=1

Contributing

cargo test --workspace # unit + integration
hoangsa-cli verify .# the repo's own template/config gates
cargo clippy --workspace --all-targets

verify is the interesting one: it checks that the prompt layer and the code still agree — that every workflow calls a CLI subcommand that exists, that the model-profile tables in the docs match model.rs role by role, that the worker skill registry in common.md matches its fallback copy in Rust. A documentation table that drifts from the code fails the build.

Two house rules:

  • Do not run cargo fmt. The tree is not uniformly rustfmt-formatted and there is a standing decision not to mass-reformat. CI format-checks newly added.rs files only — run rustfmt --edition 2024 on those.
  • plugin/ is generated from templates/ by make plugin. Edit templates/, regenerate, commit both.

License

MIT — Copyright (c) 2026 Zan

Author: Zan — @pirumu


Tiếng Việt

About

HOANGSA is a context engineering system for Claude, Codex. It solves a fundamental problem: Claude's output quality degrades as the context window fills up.

Topics

Resources

Stars

26 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages