Private Headless Automated License Uncoupling System — a self-hosted tool for AI-powered clean room software reimplementation. Feed it a dependency manifest and it runs a two-phase, isolation-enforced LLM pipeline: Agent A reads only public documentation and produces a formal specification, Agent B uses a symbiont reasoning loop to iteratively implement the package from scratch.
No user accounts. No payments. No SaaS. You run it on your own machine with your own API keys.
Documentation | Website | crates.io
cargo install phalusPre-built binaries for Linux (x86_64, aarch64), macOS (Apple Silicon), and Windows are available from GitHub Releases.
# Linux (x86_64)
curl -L https://github.com/phalus-sh/phalus/releases/latest/download/phalus-v0.6.1-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv phalus /usr/local/bin/
# macOS (Apple Silicon)
curl -L https://github.com/phalus-sh/phalus/releases/latest/download/phalus-v0.6.1-aarch64-apple-darwin.tar.gz | tar xz
sudo mv phalus /usr/local/bin/docker run -p 3000:3000 \
-e PHALUS_LLM__AGENT_A_API_KEY=sk-ant-... \
-e PHALUS_LLM__AGENT_B_API_KEY=sk-ant-... \
ghcr.io/phalus-sh/phalus:latestgit clone https://github.com/phalus-sh/phalus.git
cd phalus && cargo build --release -j2Set your API keys:
export PHALUS_LLM__AGENT_A_API_KEY=sk-ant-...
export PHALUS_LLM__AGENT_B_API_KEY=sk-ant-...Preview what would be processed:
phalus plan package.jsonRun a single package through the full pipeline:
phalus run-one npm/left-pad@1.1.3 --license mitRun all packages in a manifest:
phalus run package.json --license apache-2.0 --output ./reimplementedDry run (Agent A only, produce specs without implementation):
phalus run package.json --dry-runCross-language reimplementation:
phalus run package.json --license mit --target-lang rustInspect results:
phalus inspect ./phalus-output --audit
phalus inspect ./phalus-output --similarity
phalus inspect ./phalus-output --cspRe-validate existing output:
phalus validate ./phalus-output --similarity-threshold 0.5Resume a previous run (skip completed packages):
phalus run package.json --resumeScan a project's dependencies for license compliance:
phalus scan ./my-projectOutput:
Scan: ./my-project (42 packages from 1 manifest, 0 SBOMs)
Package Version Ecosystem License Class
lodash 4.17.21 npm MIT permissive
express 4.18.2 npm MIT permissive
serde 1.0.197 crates MIT OR Apache-2.0 permissive
numpy 2.2.6 pypi BSD-3-Clause permissive
Summary: 38 permissive, 3 copyleft-weak, 1 copyleft-strong
Supports npm, PyPI, crates.io, and Go registries. Handles CycloneDX and SPDX SBOM formats. Compound licenses (MIT OR Apache-2.0, Apache-2.0 AND ISC) are classified by their most relevant component.
| Ecosystem | Manifest | Registry |
|---|---|---|
| npm | package.json |
registry.npmjs.org |
| Python | requirements.txt |
pypi.org |
| Rust | Cargo.toml |
crates.io |
| Go | go.mod |
proxy.golang.org |
Manifest → Registry Resolver → Doc Fetcher → Agent A (Analyzer)
→ Isolation Firewall → Agent B (Builder) → Validator → Output
- Agent A reads only public documentation (README, API docs, type definitions) and produces a Clean Room Specification Pack (CSP) — 10 documents describing what the package does, never how.
- The Isolation Firewall enforces separation: Agent B never sees the original documentation or source code. Only the CSP crosses the boundary, logged with SHA-256 checksums.
- Agent B uses a symbiont ORGA reasoning loop (Observe-Reason-Gate-Act) to iteratively implement the package. It writes files, checks API surface completeness, resolves missing imports, and repeats until the implementation is complete.
- The Validator checks syntax, runs tests, scores similarity against the original, and flags anything above threshold.
Every step is recorded in an append-only audit trail.
~/.phalus/config.toml:
[llm]
agent_a_provider = "anthropic" # anthropic | openai | openrouter | ollama | any OpenAI-compatible
agent_a_model = "claude-sonnet-4-6"
agent_a_api_key = ""
agent_a_base_url = "" # optional: override API endpoint
agent_b_provider = "anthropic"
agent_b_model = "claude-sonnet-4-6"
agent_b_api_key = ""
agent_b_base_url = ""
agent_a_max_tokens = 16384 # max output tokens for Agent A
agent_b_max_tokens = 65536 # max output tokens for Agent B
[llm.retry]
max_retries = 3
initial_backoff_ms = 500
timeout_secs = 600
[isolation]
mode = "context" # context | process | container
docker_image = "alpine:3"
memory_limit = "256m"
cpu_limit = "1.0"
timeout_secs = 60
network_mode = "none"
pids_limit = 64
[limits]
max_packages_per_job = 50
max_package_size_mb = 10
concurrency = 3
[validation]
similarity_threshold = 0.70
run_tests = true
syntax_check = true
[output]
default_license = "mit"
output_dir = "./phalus-output"
include_csp = true
include_audit = true
[web]
enabled = false
host = "127.0.0.1"
port = 3000
[doc_fetcher]
max_readme_size_kb = 500
max_code_example_lines = 10
github_token = ""All config keys can be overridden via environment variables with PHALUS_ prefix and double-underscore nesting:
PHALUS_LLM__AGENT_A_API_KEY=sk-ant-...
PHALUS_LLM__AGENT_A_MODEL=claude-sonnet-4-6
PHALUS_ISOLATION__MODE=process
PHALUS_WEB__ENABLED=trueAny provider with an OpenAI-compatible /v1/chat/completions endpoint works:
# OpenAI
export PHALUS_LLM__AGENT_A_PROVIDER=openai
export PHALUS_LLM__AGENT_A_MODEL=gpt-4o
export PHALUS_LLM__AGENT_A_API_KEY=sk-...
# OpenRouter
export PHALUS_LLM__AGENT_A_PROVIDER=openrouter
export PHALUS_LLM__AGENT_A_BASE_URL=https://openrouter.ai/api
export PHALUS_LLM__AGENT_A_MODEL=anthropic/claude-sonnet-4
export PHALUS_LLM__AGENT_A_API_KEY=sk-or-...
# Ollama (local, no API key needed)
export PHALUS_LLM__AGENT_A_PROVIDER=ollama
export PHALUS_LLM__AGENT_A_BASE_URL=http://localhost:11434
export PHALUS_LLM__AGENT_A_MODEL=llama3
export PHALUS_LLM__AGENT_A_API_KEY=unusedSet AGENT_B_* equivalents for Agent B (can be a different provider/model).
| License | ID |
|---|---|
| MIT | mit |
| Apache 2.0 | apache-2.0 |
| BSD 2-Clause | bsd-2 |
| BSD 3-Clause | bsd-3 |
| ISC | isc |
| Unlicense | unlicense |
| CC0 1.0 | cc0 |
Enable the optional local web UI:
PHALUS_WEB__ENABLED=true phalus run package.jsonOr set web.enabled = true in config.toml. Serves on http://127.0.0.1:3000 by default.
This tool raises serious ethical and legal questions about open source sustainability. It exists for research, education, and transparent discourse — not to encourage license evasion. You are responsible for understanding the legal implications in your jurisdiction. The legality of AI-assisted clean room reimplementation is unsettled law.
This project replicates the core pipeline demonstrated by Malus, presented at FOSDEM 2026 by Dylan Ayrey and Mike Nolan. PHALUS strips the concept down to the essential machinery: the pipeline, the isolation, and the audit trail.
0BSD
