Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,43 @@ jobs:
node bin/agentic-kit.mjs x reference sync
node -e "const fs=require('fs'),os=require('os'),p=require('path').join(os.homedir(),'.claude','CLAUDE.md'); const t=fs.readFileSync(p,'utf8'); for (const s of ['ruflo-preamble','ruflo-reference']) if(!t.includes('<!-- BEGIN '+s+' -->')) throw new Error('missing block '+s); console.log('blocks OK')"
node bin/agentic-kit.mjs uninstall --dry-run

# Static quality gates. Platform-independent → single OS. This is the only job
# that installs devDependencies (the published package stays zero-runtime-dep).
quality:
name: quality (typecheck, lint, build, audit)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v7
with:
node-version: 22
cache: pnpm

- name: Install devDependencies
run: pnpm install --frozen-lockfile

- name: Typecheck (tsc --checkJs)
run: pnpm run typecheck
- name: Lint (eslint)
run: pnpm run lint
- name: Markdown lint
run: pnpm run lint:md
- name: Build (packaging + load validation)
run: pnpm run build
- name: Dependency audit
run: pnpm run audit

# Internal/relative links only (fast, deterministic). External links run in
# nightly — network + rate-limits make them flaky per-PR.
links:
name: links (internal)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check internal links (offline)
uses: lycheeverse/lychee-action@v2
with:
args: "--offline --config lychee.toml README.md CLAUDE.md 'docs/**/*.md'"
fail: true
13 changes: 13 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,16 @@ jobs:
run: |
node bin/agentic-kit.mjs x verify security
node bin/agentic-kit.mjs x verify learning

links-external:
name: links (external)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# External link validation runs here, not on PRs: network + rate-limits
# (npm/GitHub 403 bots) make it flaky per-PR. Config + excludes: lychee.toml.
- name: Check all links (internal + external)
uses: lycheeverse/lychee-action@v2
with:
args: "--config lychee.toml README.md CLAUDE.md 'docs/**/*.md'"
fail: true
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ test-*.log

# Dogfooding artifacts — running ruflo init / aqe init / ruflo-onboard against THIS
# repo writes these. They are NOT source (see CLAUDE.md "Dogfooding artifacts are not
# source"); never commit them.
# source"); never commit them. The authored instruction files (CLAUDE.md for claude,
# AGENTS.md for codex) ARE tracked; only their generated dirs (.claude/, .agents/) and
# local overrides (.codex/) are ignored.
.agentic-qe/
.claude/
.agents/
.codex/
.mcp.json
ruvector.db
*.db
Expand Down
5 changes: 5 additions & 0 deletions .lycheeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# URL patterns to skip in link checks (one regex per line).
# Example placeholders / non-resolvable references go here.
^https?://localhost
^https?://127\.0\.0\.1
^https?://example\.(com|org)
26 changes: 26 additions & 0 deletions .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
// Lint only OUR authored markdown. Vendored ruflo/aqe docs (.claude, .agentic-qe,
// .agents) and archived docs are excluded — not ours to fix.
"globs": [
"README.md",
"CLAUDE.md",
"AGENTS.md",
"docs/**/*.md"
],
"ignores": [
"node_modules",
".claude",
".agentic-qe",
".agents",
"docs/archive"
],
"config": {
"default": true,
"MD013": false, // line length — prose/tables wrap naturally
"MD033": false, // inline HTML — used deliberately in docs
"MD041": false, // first line need not be a top-level heading
"MD024": { "siblings_only": true }, // allow repeated headings in different sections
"MD029": { "style": "ordered" },
"MD060": false // table pipe-alignment — cosmetic, fights hand-maintained wide tables
}
}
40 changes: 40 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!-- Codex-side project instructions (mirror of CLAUDE.md). Full ruflo + agentic-qe
operating guidance lives machine-wide at ~/.codex/AGENTS.md / ~/.claude/CLAUDE.md. -->

# Ruflo Machine Ref (Codex / AGENTS.md)

This repo (`@pacphi/agentic-kit`) is a plain-ESM Node.js CLI — **zero runtime
dependencies**; only `bin/`, `src/`, and `claude/` ship. Tooling (eslint, tsc
`--checkJs`, markdownlint, lychee) is devDependencies only. Codex reads this file
the way Claude Code reads `CLAUDE.md`; keep the two in sync.

## Swarm Config

- **Topology**: hierarchical-mesh (anti-drift)
- **Max Agents**: 15
- **Memory**: hybrid
- **HNSW**: Enabled
- **Neural**: Enabled

```bash
ruflo swarm init --topology hierarchical --max-agents 15 --strategy specialized
```

## Build & Test

```bash
pnpm test # node --test unit suite + statusline segments
pnpm run check # typecheck + lint + markdown lint + build + test
pnpm run build # packaging + CLI-load validation (no transpile — plain ESM)
```

## Operating rules

- Do what's asked; nothing more. Prefer editing existing files over new ones.
- Never commit secrets or `.env` files. Never auto-commit/push without an explicit ask.
- **No `Co-Authored-By` trailer** unless `.claude/settings.json` sets `attribution.commit`.
- Keep files under ~500 lines; validate input at boundaries.

## Agentic QE v3
<!-- managed by ruflo-setup-aqe — aqe init skips regeneration when this sentinel is present -->
<!-- see ~/.claude/CLAUDE.md for full AQE operating guidance -->
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ prints its plan with reasons — you always see the impact before anything chang
What the verbs cover:

| Verb | What it does |
|------|--------------|
| ------ | -------------- |
| **setup** | Installs/updates ruflo + agentic-qe globally (handling npm ≥11.17's `allow-scripts` so natives build), deploys the token-audit skill, merges the managed guidance blocks into `~/.claude/CLAUDE.md`, offers one-time MCP registration (user scope, with a tool-family picker), and — inside a repo — initializes the project: sanitized `ruflo init`, absolute memory-path pin, a **verified** store→disk write, statusline footer, and a background daemon with **local-only ($0) workers** (token-spending AI workers stay opt-in behind upstream's machine-wide budget). Project scope triggers on a `.git` directory in the current folder; without one it's skipped with a note. `--project` forces it anyway (e.g. a not-yet-`git init`-ed folder), `--minimal` skips it, `--yes` accepts all prompts (non-interactive), `--no-aqe` / `--no-security` disable those subsystems, and `--reconfigure` re-offers MCP registration. |
| **status** | Per-subsystem ✓/⚠/✗ (versions, the kit's own version, natives, security, learning, aqe/RVF, MCP, **hosts** (claude/codex — version + install method, or "enabled but not installed"), **providers** (host wiring + aqe fallback chain, or "drifted"/claude-only default), daemons, CLAUDE.md blocks, statusline), each drift row naming what `sync` would do about it. |
| **sync** | The one convergence verb: upgrades first when a new release exists, then re-heals everything an upgrade wipes, then re-checks and reports. Included in that heal: it **installs any enabled frontier host** (claude/codex) that's entirely absent — never touching an external (mise/brew/native) install — and **re-applies provider wiring** (the `ENABLE_*` host env, the aqe fallback chain, and ruflo API providers) whenever it has drifted. It also **self-updates the kit**: when a newer `@pacphi/agentic-kit` exists it installs it as the *last* step (the new code applies from the next `ak` run, never mid-sync). Prerelease installs (`4.0.0-alpha.*`) track the `next` npm dist-tag as well as `latest`, so alphas see their successors; stable installs only ever follow `latest`. `--no-upgrade` skips the self-update along with the package upgrades. |
Expand Down Expand Up @@ -91,7 +91,7 @@ you opt in. Two independent axes:
install (mise/brew/native) is detected, reused, and never shadowed.
- **Providers** — which LLM the routers use, independent of the host: agentic-qe's
`AQE_LLM_PROVIDER` (`claude-code`/`claude`/`openai`/`gemini`/`openrouter`/`azure-openai`/
`bedrock`/`cognitum`/`ollama`) plus an ordered fallback chain, and ruflo's API providers.
`bedrock`/`cognitum`/`ollama`/`onnx`) plus an ordered fallback chain, and ruflo's API providers.
API keys stay in the environment — never written to `kit.json`.

`ak x provider status` shows what's detected and wired; `ak x provider pick` chooses and
Expand Down
1 change: 1 addition & 0 deletions bin/agentic-kit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ async function main() {
return 0;
}

/** @type {Record<string, () => Promise<any>>} */
let table = PORCELAIN;
if (cmd === 'x') {
table = PLUMBING;
Expand Down
25 changes: 17 additions & 8 deletions docs/PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,50 @@ Install `ak`, run `ak setup`. Claude Code is the host, agentic-qe uses its own d
nothing about providers is written anywhere. This is the whole feature for most people:
**it already works, and `kit.json` stays at its defaults.**

```
```bash
ak setup # claude just works; codex/other providers are opt-in
ak status # shows a "hosts" + "providers" row so you can see what's true
```

If you happen to have `codex` installed, `ak` notices and *offers* — it never flips it on
for you:

```
```text
ℹ codex CLI detected — run `ak x provider pick` to let ruflo use both claude and codex
```

## Level 1 — turn on codex (one command)

```
```bash
ak x provider pick
```

An interactive picker (or flags for scripts). Enable `codex` and `ak`:

- installs it if it's missing (`npm i -g @openai/codex`) — but leaves an existing
mise/brew/native install alone,
- runs `ruflo init --dual` (ruflo's "Claude Code + Codex hybrid" mode),
- writes `ENABLE_CLAUDE_CODE` / `ENABLE_CODEX` into `.claude/settings.local.json`.

```
```bash
ak x provider pick --host claude,codex --yes # non-interactive
```

## Level 2 — choose which LLM runs QE

agentic-qe can run its analysis on any of: `claude-code` (your Claude subscription),
`claude` / `openai` / `gemini` / `openrouter` / `azure-openai` / `bedrock` / `cognitum`
(metered API key), or `ollama` (local).
(metered API key), or `ollama` / `onnx` (local).

```
**Billing is the axis that isn't obvious from the names** — three categories:
`claude-code` runs on your Claude plan ($0 metered), `ollama` and `onnx` are local ($0),
and **everything else bills a metered API key**. `claude-code` is the *only* subscription
option here: the codex and gemini CLIs also support OAuth/subscription login, but that
lives on the **host axis** (Level 1, which CLI runs the loop) — not as an aqe provider
*type*. So there's no `openai`-subscription or `gemini`-subscription entry; their OAuth
paths are reached by enabling those *hosts*, while the provider list is API-metered.

```bash
ak x provider pick --aqe-provider claude-code # run QE on your subscription, no API bill
```

Expand All @@ -66,7 +75,7 @@ router will **auto-enable** OpenAI as a fallback on its own — you don't have t
When you want explicit ordering rather than env auto-enable, `ak` manages agentic-qe's
`.agentic-qe/llm-config.json` from `kit.json`:

```
```bash
ak x provider pick \
--aqe-provider claude-code \
--aqe-fallback 'claude-code:claude-opus-4-8; openai:gpt-5.6; gemini:gemini-3.5-flash'
Expand Down Expand Up @@ -101,7 +110,7 @@ If you hand-edit `.agentic-qe/llm-config.json` yourself and *don't* use `ak`'s

## Undo, always

```
```bash
ak x provider off # reset to the claude-only default, reversibly
```

Expand Down
2 changes: 1 addition & 1 deletion docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fix; `sync` applies them in the right order and re-checks afterward.
## Common situations

| Symptom | What's happening | Fix |
|---|---|---|
| --- | --- | --- |
| Just upgraded ruflo/agentic-qe (`npm i -g …`) and things feel off | Upgrades re-resolve dependencies: native SQLite bindings and the aidefence package get dropped, the statusline is regenerated without the footer | `ak sync` (this is its main job) |
| `status` shows `natives … WASM fallback` | agentdb resolved a non-native better-sqlite3 — on this path **memory writes can silently vanish**. Root cause is npm ≥11.17 blocking install scripts during upgrades | `ak sync` installs the native binding |
| `status` shows `aidefence missing` | ruflo ≥3.28 stopped shipping `@claude-flow/aidefence` but `ruflo security defend` still imports it — injection defense is silently non-functional ([ruvnet/ruflo#2670](https://github.com/ruvnet/ruflo/issues/2670)) | `ak sync` reinstalls it; `ak x verify security` proves defend works (exit 1=threat / 0=clean) |
Expand Down
60 changes: 60 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Flat ESLint config. Scope: OUR code only (src/bin/tests/scripts). Vendored
// ruflo/aqe content (.claude, .agentic-qe, .agents) and historical docs are
// never linted — they aren't ours to fix and would drown real findings.
import js from '@eslint/js';
import globals from 'globals';

export default [
{
ignores: [
'node_modules/**',
'.claude/**',
'.agentic-qe/**',
'.agents/**',
'docs/archive/**',
'coverage/**',
],
},
js.configs.recommended,
{
files: ['**/*.{mjs,js,cjs}'],
languageOptions: {
ecmaVersion: 2023,
sourceType: 'module',
globals: { ...globals.node },
},
rules: {
// High-signal correctness rules; not a style bikeshed.
'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'no-undef': 'error',
'no-constant-condition': ['error', { checkLoops: false }],
'no-empty': ['error', { allowEmptyCatch: true }],
'prefer-const': 'error',
'no-var': 'error',
'no-eval': 'error',
eqeqeq: ['error', 'smart'],
},
},
{
// CommonJS test/statusline files use require/module.
files: ['**/*.cjs'],
languageOptions: { sourceType: 'commonjs' },
},
{
// The statusline footer is an EMITTED shell-statusline template + its test:
// deliberately old-school (var, literal ANSI escape bytes, bare catch bindings)
// because the snippet runs embedded in the user's shell, not as normal source.
// Relax the idiom rules here; syntax/undef checks still apply.
files: ['src/templates/statusline-footer.cjs', 'tests/statusline-segments.test.cjs'],
// getStdinData is injected by the host statusline runtime (guarded with typeof).
languageOptions: { globals: { getStdinData: 'readonly' } },
rules: {
'no-var': 'off',
'no-redeclare': 'off',
'no-control-regex': 'off',
'no-unused-vars': 'off',
'no-useless-assignment': 'off',
'prefer-const': 'off',
},
},
];
29 changes: 29 additions & 0 deletions lychee.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Link checker config (internal + external). Scope is set by the invoking glob
# in CI/scripts (our authored docs), and vendored trees are excluded below so we
# never validate ruflo/aqe's links.
#
# On PRs we check INTERNAL/relative links only (fast, deterministic); external
# links run in nightly (network + rate-limits make them flaky per-PR).

# Treat these as success (GitHub/CI sometimes rate-limits or 403s bots).
accept = [200, 206, 429]

max_retries = 2
retry_wait_time = 2
timeout = 20
max_concurrency = 8

# Don't descend into vendored or archived trees.
exclude_path = [
"node_modules",
".claude",
".agentic-qe",
".agents",
"docs/archive",
]

# Hosts that reliably 403/rate-limit automated requests — noise, not broken links.
exclude = [
"^https://img\\.shields\\.io",
"^https://www\\.npmjs\\.com", # npm package pages 403 bots/CI
]
23 changes: 22 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,28 @@
"docs/TROUBLESHOOTING.md"
],
"scripts": {
"test": "node --test \"tests/kit/*.test.mjs\" && node tests/statusline-segments.test.cjs"
"test": "node --test \"tests/kit/*.test.mjs\" && node tests/statusline-segments.test.cjs",
"typecheck": "tsc -p tsconfig.json",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:md": "markdownlint-cli2",
"lint:md:fix": "markdownlint-cli2 --fix",
"lint:links": "lychee --config lychee.toml README.md CLAUDE.md AGENTS.md 'docs/**/*.md'",
"lint:links:internal": "lychee --offline --config lychee.toml README.md CLAUDE.md AGENTS.md 'docs/**/*.md'",
"build": "node scripts/build-check.mjs",
"audit": "pnpm audit --audit-level=moderate",
"audit:fix": "pnpm audit --fix",
"outdated": "pnpm outdated",
"upgrade": "pnpm up",
"check": "pnpm run typecheck && pnpm run lint && pnpm run lint:md && pnpm run build && pnpm test"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/node": "^26.1.1",
"eslint": "^10.7.0",
"globals": "^17.7.0",
"markdownlint-cli2": "^0.23.0",
"typescript": "^7.0.2"
},
"repository": {
"type": "git",
Expand Down
Loading
Loading