Skip to content
dsh.fish
Bundle

dsh-cortex

Cortex — 低成本高质量多模型递归任务编排、模型评测与智能路由平台(DSH 插件):任务画像/策略匹配/递归拆解/动态路由/四级质量门控/批量监督/恢复引擎/预算控制/策略沉淀/KPI

Source
iguowz
installs
1 installs
stars
1 stars
License
MIT
Updated
Updated yesterday

Readme

# Cortex — Multi-Model Orchestration & Evaluation for DeepSeek-Harness

[![npm version](https://img.shields.io/npm/v/dsh-cortex)](https://www.npmjs.com/package/dsh-cortex) [![npm downloads](https://img.shields.io/npm/dm/dsh-cortex)](https://www.npmjs.com/package/dsh-cortex) [![license](https://img.shields.io/npm/l/dsh-cortex)](https://github.com/iguowz/dsh-cortex/blob/main/LICENSE)

**English** | [中文](./README.zh-CN.md) | [npm package](https://www.npmjs.com/package/dsh-cortex) | [GitHub](https://github.com/iguowz/dsh-cortex)

Cortex is a [DeepSeek-Harness](https://npmjs.com/package/@deepseek-ai/dsh) plugin that turns the host's **primary (strong) model** into a **high-leverage supervisor**. The supervisor plans, decomposes, verifies and accepts; **routed executor models** (small/cheap models such as `Qwen3.8-9B`) and tools do the heavy lifting. With a recursive task tree, dynamic routing, four-stage quality gates, budget control, failure recovery, policy reuse and per-dimension model evaluation, Cortex keeps quality stable while driving the unit cost of successful tasks down.

The **supervisor** is the host primary model that drives the `cortex_*` tools (e.g. `deepseek-v4-pro` in the bundled registry), and **executors** are the models the dynamic router picks per subtask (L1/L2 tiers, e.g. `Qwen3.8-9B`).

> Suggested repository topics (GitHub): `dsh-plugin` · `dsh` · `cordis` · `llm-orchestration` · `multi-model` · `model-routing` · `quality-gate`

---

## Highlights

| Capability | Entry | Notes |
|---|---|---|
| Task intelligence | `cortex_start` | Profile → fingerprint → strategy match (≥0.90 reuse / 0.70~0.90 light-check / <0.70 replan) → budget pool → granularity check |
| Recursive task tree | `cortex_decompose` | Safety limits: maxDepth 6 / maxTotalNodes 50 / maxChildrenPerNode 10 / **maxReplan 3**; DAG `depends_on`; aggregate nodes merge children by node schema **+ Gate0**, active-model only |
| Recursive execution | `cortex_execute recursive` | Ready leaves auto-scheduled, aggregate nodes merged; **evaluate:gate2 / multi_vote pass through** — same standard as manual batch |
| Caching | engine built-in | **L1 exact + L2 semantic (near-duplicate text similarity, conservative 0.88 threshold, skip-able) + L3 cross-task component reuse** |
| Drift & value | engine built-in | Model **drift monitoring** vs static baseline (auto routing penalty, surfaced in registry/matrix) + **value score & Pareto frontier** per evaluation run |
| Dynamic routing | `cortex_execute` | Candidate filter → utility scoring (quality/success/risk − cost/latency/failure) → **MQC** upgrade gate; costFirst / balanced / qualityFirst; multi-model vote |
| Quality gates | Gate0 deterministic · Gate1 self-check · Gate2 evaluator · Gate3 `cortex_review` · **Gate3.5 red-team** | Hard fails: format_validity / safety / groundedness < 0.5; review decisions carry node quality/Gate1 context snapshots; **red-team** adversarially challenges high-impact acceptances (S/M, risk≥0.5 or quality≥0.9) — material defect → downgrade to retry |
| Recovery engine | `cortex_recover` | Failure taxonomy → retry / switch / prompt-fix / decompose / upgrade / human + failure-pattern learning |
| Soft-defect correction | `cortex_execute` / `cortex_recover` | Soft cap `max_delegations` (default 3): a capable-but-insufficient result is corrected in place (same model → better model → escalate to supervisor); optional **continuable sub-session** (`config.continuableCorrection`) keeps context across rounds; hard failures still use type-based recovery |
| Price override | `cortex_models` / UI / CLI | Set/clear a model's effective price (`price`/`clear_price`, or `/cortex models set-price|clear-price`) — **3-tier priority: model/provider authoritative > user-set > default**; persisted; routing prices with the effective value |
| Budget control | engine built-in | 4 pools (10/70/10/10), STOP-1..4 (**STOP-2 from observed MQC — real ΔQ/ΔC, not hard-coded**), 90% high-cost lock, degraded mode |
| Model evaluation | `cortex_evaluate` | 7-dim scoring per case; **per-model × task-type × capability × 7-dim profile** (`dims_profile`, EMA, persisted across restarts; also fed by production Gate2/`cortex_review` dims); **dynamic capabilities** (profile-thresholded caps auto-register into the catalog and union with static capabilities at routing); Rule-First deterministic correctness for structured `expected`; UI **one-click run**; **value score (Q×SR/Cost) + Pareto frontier**; **drift monitoring** (vs static baseline → automatic routing penalty) |
| Model registry | `cortex_models` (`config/models.yaml`) | Static YAML + DSH `ctx.llm` dynamic discovery + enable/disable management; routing scores (ranking preview) |
| Policy center | `cortex_policy` / `cortex_strategy_match` | Fingerprint similarity, versioned policies, skip-level tree suggestions |
| KPI | `cortex_report` | Supervisor calls/task, **A-cost breakdown by call kind (start/decompose/review/…)** (aByKind), supervisor leverage, saving vs direct primary-model run (negative → orchestration warning), quality, policy reuse rate |
| Web console | `/cortex ui` / 8788 | Trends / timeline / model registry / capability matrix (4 metrics + **7-dim rows**) / evaluation center (case library + results), i18n zh+en, light/dark theme, CNY/USD display, SSE live updates |
| Watchdog | `/cortex watchdog` / `/watchdog` | Cross-workspace timed task injection + goal-reached auto-iteration: **schedule** (`--at/--after/--every`, every ≥300s) injected via the official inbox channel (`agent.followup` — never writes session events), **goal-loop** (set goals; after an injected/executed task, the strong model objectively evaluates the conversation against the goals and re-injects improvement guidance until met (met+score **double gate**) or `maxRounds` reached), **task-list** (ordered task chain, each auto-advanced after the previous completes); **work windows** (global `ws window <HH:MM-HH:MM>`, cross-midnight/days supported), startAt/endAt, cross-workspace (`ws:`/`session:`/`workspaceId`/`workspacePath` targets); web console `/watchdog` + `/api/watchdog/*`; **consecutive eval failures terminalize to `failed`** (observable) |

## Install & Auto-Enable

`dsh plugin` is the supported way: it installs the package into the profile, and because this package declares `dsh.bundle.patch` (= `cordis.patch.yml`), it is **automatically appended to `dsh.profile.bundles`** — enabled on next boot with no manual profile edits.

**From npm (published):**

```bash
# install the plugin package as a dependency
yarn add dsh-cortex            # or: npm install dsh-cortex

# register it into a DSH profile and boot
npx @deepseek-ai/dsh plugin --profile web add dsh-cortex
npx @deepseek-ai/dsh web        # boot — the 13 cortex_* tools are live
```

**From a local checkout (development):**

```bash
cd <repo-path>                                   # the repo root
npx @deepseek-ai/dsh plugin --profile web add .  # anchors to this dir (or pass the absolute path)
npx @deepseek-ai/dsh web
```

**Remove:** `npx @deepseek-ai/dsh plugin --profile web remove dsh-cortex`.

The shipped bundle patch inserts the `cortex` row with `uiEnabled: true, uiPort: 8788` (console listens on loopback only). `stateDir` and `modelsFile` use built-in defaults (`$DSH_HOME/storages/cortex` and the bundled `config/models.yaml`) — anything can be overridden by an `- id: cortex` config row in your profile's own `cordis.patch.yml` (it applies after bundle layers).

## Typical Flow (agent view)

```
cortex_start → (cortex_strategy_match) → cortex_decompose T0 → cortex_execute [node_ids | recursive]
→ cortex_review (batch accept) → cortex_recover (on failures) → cortex_report (KPI) → cortex_policy (settle)
```

## Operations & Commands

### 1. Agent tools (13 — the supervisor calls them autonomously)

| Tool | Purpose | Key parameters |
|---|---|---|
| `cortex_start` | Create a task (profile → fingerprint → strategy match → budget pool) | `goal`, `profile{task_type, domain, complexity, risk, quality_requirement, budget_limit, input_tokens?, expected_output_tokens?, latency_requirement_ms?, language?, capability?}`, `input` |
| `cortex_strategy_match` | Policy-center lookup (3-tier reuse verdict) | `profile` |
| `cortex_decompose` | Split a parent node (safety limits / DAG / replace; **large-text split**: `children[].split {count?, by?}` auto-splits into N parallel shard executors + 1 aggregator) | `task_id`, `parent_id?`, `replace?`, `children[{goal, task_type, capability, output_schema, quality_target?, tool_allow?, depends_on?, type?, split?}]` |
| `cortex_execute` | Route & execute (Gate0/1[/2], cache, accounting) | `task_id`, `node_id?`/`node_ids?`, `recursive?`, `mode?` (costFirst|balanced|qualityFirst), `multi_vote?`, `max_parallel?`, `force_models?`, `evaluate?` (none|gate2), `max_delegations?` |
| `cortex_review` | Gate3 batch acceptance (decisions carry quality/self-check snapshots; **Gate3.5 red-team**) | `task_id`, `decisions[{node_id, status, reason_code?, missing_items?, next_action, recommended_depth?, confidence?}]`, `auto?`, `red_team?` |
| `cortex_recover` | Recovery decision tree (retry/switch/upgrade re-run in-engine) | `task_id`, `node_id?` |
| `cortex_policy` | Settle a policy from a successful task | `task_id`, `note?` |
| `cortex_report` | KPI report (per task or global) | `task_id?` |
| `cortex_models` | Model registry / profiles / routing scores / drift / **price override** | `task_type?`, `capability?`, `model?`, `enabled?`, `refresh?`, `reset?`, `price?`, `clear_price?` |
| `cortex_evaluate` | Model evaluation (7-dim × capability profiles, value/Pareto) | `cases?`, `use_saved?`, `models?`, `task_type?`, `quality_target?` |
| `cortex_eval_cases` | Eval-case library (page + conversation shared) | `action?` (list|add|remove), `input`, `goal`, `capability`, `expected`, `output_schema`, `id` |
| `cortex_capabilities` | Capability catalog (append-only) | `action?` (list|add), `name`, `description?` |
| `cortex_l0` | L0 deterministic tool library (list/show/add/remove/generate/run) | `action?`, `keywords`, `allowed?` |

### 2. Slash commands (`/cortex <subcommand>`)

| Command | What it does |
|---|---|
| `/cortex status` | Engine state: tasks (running), nodes, attempts, policies, models, **discipline status** |
| `/cortex task <id>` | Task tree (profile/strategy/budget/nodes) |
| `/cortex trace <id>` | Execution trail (attempts + decisions) |
| `/cortex kpi [id]` | KPI report (global or per task) |
| `/cortex models [enable\|disable <id>\|refresh\|reset\|set-price <id> <in> <out> [cached]\|clear-price <id>]` | Registry listing; `reset` clears evaluation feedback; enable/disable toggles; refresh re-discovers dynamic models; `set-price`/`clear-price` set/clear a model's effective price (persisted, 3-tier priority) |
| `/cortex policies [disable|enable <id>]` | Policy library + controlled enable/disable (rollback = re-enable) |
| `/cortex model-pref [set <id> [reason]\|clear\|show]` | Set/clear the **preferred executor model** with **preference content** (`reason` = which tasks it suits): routing adopts it when the task scene is *covered* by the content (>=50%) + active + quality <0.9 (user preference is authoritative — capability tags are advisory only, `prefCapabilityMismatch` audited; failed executions auto-upgrade via the recovery engine); persisted; same as page ★ |
| `/cortex l0` | L0 deterministic tool library (list/show/remove/generate/run) |
| `/cortex rate [refresh]` | USD→CNY rate (refresh forces fetch) |
| `/cortex reset` | Delete state files + clear in-memory store + reload static registry + **immediately re-discover models from DSH** (no host restart needed); newly discovered third-party models are **dedup-merged into `config/models.yaml`** (append-only, comments preserved) so they join the static registry permanently |
| `/cortex ui start|stop|status` | Local console control |
| `/cortex watchdog <add task\|add goal\|list\|rm\|pause\|resume\|run\|goal\|ws\|ui>` | Watchdog: cross-workspace scheduled task injection (at/after/every, ≥300s) + goal-loop auto evaluation & remediation until reached (startAt/endAt optional; **global** work window 09:00–18:00; `ws window` to set/clear; consecutive eval failures terminalize to "failed" for visibility) |
| `/cortex routing [suggest\|show\|apply\|rollback]` | Route-weight learning: sample-driven weights suggestion (suggest), show current, one-click apply, rollback — automation driven by per-node routing samples + drift |
| `/cortex budget` | Budget rebalancing: shared-pool balance + ledger (dynamic reclaim/re-distribution) |
| `/cortex calibration` | Evaluator-calibration chain (historical contradictory samples across review vs self-check vs terminal state) |
| `/cortex help` | Command usage |

### 3. Console REST (127.0.0.1:8788)

```
GET  /api/overview · /api/timeline?hours=all|24|168 · /api/rate · /api/models
     /api/matrix · /api/evaluations · /api/eval-cases · /api/capabilities
     /api/evaluate/status · /api/task/<id> · /api/events (SSE live)
POST /api/models/<id>            {enabled?: boolean, preferred?: boolean, reason?: string}   // reason = preference content (required on the page)
     /api/matrix/reset           (clear evaluation feedback)
     /api/eval-cases             {action: add|remove|save, ...}
     /api/capabilities           {name, description?}
     /api/evaluate               {models?, cases?, use_saved?} (real background run)
     /api/watchdog               {action: add-task|add-goal|pause|resume|remove|run|window-set|window-clear|ws-add, ...} (whitelisted)
GET  /watchdog · /api/watchdog/rules|runs?limit=50|targets|windows   (watchdog page, uses /api/events SSE)
```

### 4. Runtime lifecycle

- **Mount**: `apply` → registry load (static YAML + persisted overrides + model states) → heartbeat `stateDir/mounted.json` → optional console → usage-settle timer (60s, zombie sweep every 5 ticks) → dynamic model discovery.
- **Per turn**: orchestration-discipline context is injected **per conversation session** (suppressed only when that session has a flow active within 15 min); other sessions' leftover flows never suppress.
- **Unmount / restart**: effect dispose stops the console (**active SSE connections destroyed** — no hang) and clears timers; everything durable lives in the state dir (tasks/nodes/policies/profiles/model states/rate) and rebuilds on restart (last-write-wins).
- **Self-healing**: zombie tasks (running, 4h silent) are finalized automatically; evaluation feedback and drift baselines survive restarts; `/cortex reset` wipes state files for a fresh start (**instant**: store cleared, static registry reloaded, then DSH re-discovered); dynamic model discovery also refreshes automatically **once a day** (`modelRefreshHours`, default 24, 0=off).

## Model Allocation (sub-agent pipeline)

- **Sensitivity tiers** (driven by `qualitySensitiveOf`): `S` (complex planning / arbitration / final review / correction — needs strong reasoning), `M` (planning / numeric-statistics / key evaluation / visual detail — weak models may repeat & vote), `L` (regular execution). Decision records carry `sensitivity`.
- **Strongest fallback chain** (`strongestOf`): configured `strongestModel` (must be active) → else **derived from live profiles** (tier → defaultQuality → measured quality → exec success rate). If no strongest model is configured, **the current best available model IS the strongest** — S-tier roles never stall; the mapping shifts dynamically as profiles update.
- **Sub-agents per node**: `planAgent` (`cortex_decompose auto:true` — strongest model generates children), `reviewAgent` (`cortex_review auto:true` — threshold auto-accept for regular nodes + review sub-agent for anomalies/high-sensitivity), `fixAgent` (`config.fixAgentAuto` — on escalation/upgrade the strongest model may deliver a fix or the corrected answer directly).
- **Weak-model voting** (`repeat_vote`, M/S tiers): the same model executes N rounds (2-5) and results are merged by agreement (pass/evaluate/arbitrate) — reliability of a strong model at ~1/100 cost.
- **Deterministic statistics** (V8.0 §5.1 L0 tier): statistics/counting nodes become "**extract (model, vote/early-stop) → majority-merged records → engine computation**" — the model only extracts records (EXTRACT_CONTRACT); counts/aggregations are computed by `lib/engine/compute.js` (zero cost, replayable), eliminating model-count drift; `type:"compute"` = L0 engine node (decompose accepts `compute:{ops:[...]}`, inferred from goal by default) — results carry `quality_source:"engine"` (E tier, auto-accepted without supervisor review).
- **Pure-text statistics direct compute**: word frequency / char / word / line counts — **text is the data**: the engine tokenizes and counts the source text directly (zero model calls, exact to each token, reproducible); entity-level stats still go extract+engine.
- **V8.0 metrics**: `cortex_report` adds node autonomy rate (autonomyRate), S-tier cost share (cost.sShare) and voting/engine stats (voting: repeat attempts/cost, engine computes, estimated saving); UI report cards updated.
- **L0 capability library**: AI-generated deterministic tools accumulate at runtime (`stateDir/l0_capabilities.json`, versioned) — execution checks first (id/name/keyword match → zero-cost engine run; explicit `l0:"id"` missing + allowed → strongest model generates code → **sandbox verification** (vm zero-trust / forbidden tokens / timeout / double-run determinism / sample+Gate0) → stored → executed; unverified code never runs); auto-disable after 3 consecutive failures; `cortex_l0`, `/cortex l0`, "L0 tools" UI tab.
- **Auto mode**: `autoMode(task)` — quality_requirement≥0.9 ∥ complexity≥0.8 ∥ risk≥0.8 → `qualityFirst` automatically (no manual mode).
- **§7.1 KPIs**: convergence rate / avg tree depth / cache hit rate (task-level + global, deterministic definitions); attempts now carry `fromCache`/`cacheLevel` (cache hits observable); no duplicate cache rows on hit (same-key idempotent).
- **§4.13 learning chain ⑤ + §7.1 global model usage**: distillation dataset `stateDir/distill.jsonl` — L3 (strongest tier) high-quality outputs (execution / multi-vote consensus / S-delegated plan·review·fix·L0 generation) auto-collected when quality ≥ distillMinQuality (0.9), capped at 500 rows, observable via report `distill{rows,models,lastAt}`; globalKpi models gains `tierUsage`/`upgradeRate`/`fallbackRate`.
- **Domain-dimension profiles** (§4.12 model×domain×task-type): `domain_profiles[domain][taskType/cap]` — EMA write-back from evaluation/Gate2 (same alpha, cross-restart deep-merge persistence); routing fallback chain **domain → type-level → 7-dim mean → default** (`predictQuality(model, node, env.domain)`); `cortex_evaluate` adds `domain` param (single-domain case set auto-inherits); `cortex_models` displays domain profiles.

## Model Profiles (how they update)

- **Evaluation write-back** (`cortex_evaluate` / one-click UI run): per task-type quality EMA + success rate + cost/latency + 7-dim capability profiles (`dims_profile`), persisted in `profile_overrides.json` (drift baselines anchored at first measurement).
- **Execution feedback**: every real node execution (non-cache) updates deterministic counters — attempts/complete/failed + failure-type & task-type distributions, persisted in the same file; when samples >= 3 (`EXEC_PROFILE_MIN_SAMPLES`), routing uses the **measured** success rate instead of the static one (the more it is used, the truer the profile, the better the routing). Quality scores still come from evaluations only (Gate1 self-checks never pollute profiles).
- `POST /api/matrix/reset` or `/cortex models reset` restores static baselines (evaluation + execution feedback).
- **Measured-only scores**: the capability matrix shows a value **only for verified capabilities** (evaluation/execution write-back keys, tracked in `measured`); static declarations and `defaultQuality` never masquerade as verified scores — unverified cells display "no measured data".

## Sub-Model Capabilities & Media Support

Executors (routed sub-models) are self-contained worker agents. What they can and cannot do:

**Capability dimensions** include media tags: `image_analysis` (declared by vision-capable models — image tasks filter by it) and `audio_video_analysis` (catalog dimension; no model declares it yet — matrix stays empty until a media-capable model/MCP is configured). Decompose image subtasks with `capability: ['image_analysis']` (not `document_analysis`). **Route-time closure**: for nodes with image input, routing merges `image_analysis` into the need and applies an AND-hard-filter for media-exclusive capabilities — text-only models (even strong tiers) are excluded at routing (executor pre-check stays as the second line; `force_models`/preferred paths remain authoritative and call the user-chosen model).

| Dimension | Supported |
|---|---|
| Input | text, files (read/glob/grep), **images** (read_image / MCP browser), URLs (web_search/web_fetch, read-only) — also **base64 images** (`data:image/...;base64` or `{image_base64, mime}`) auto-decoded to a real file for the executor |
| Tools (agent mode) | `read` `glob` `grep` `read_image` + **`web_search`/`web_fetch`** (read-only, default; override via `executorExtraTools`) + **`mcp__*`** (any configured MCP server — e.g. Playwright screenshots) + `skill` + business-plugin prefixes (default `tssdp_`) |
| Policy | `mediaPolicy`: `auto` (default — media input forces agent mode + contract), `reject` (explicit fast-fail with diagnosis), `pass_through` (hand to MCP) |
| Output | structured JSON **+ optional top-level `artifacts` [{path, mime}]** — engine validates existence & magic bytes (png/jpeg/webp/gif/mp4/mp3/wav/pdf); invalid → node `failed` with audit trail |
| By default denied | write/edit/shell (`pwsh`/`bash`/`run_code`) and re-orchestration (`subagent`/`workflow`/`cortex_*`/…) — an explicit per-node `tool_allow` swaps in a custom allow list for artifact-producing tasks |
| Honest limits | DSH provider modalities are **text + image only** — audio/video *understanding* requires a media-capable MCP/multimodal route; otherwise the executor returns the `{"unsupported": true, "reason": ...}` contract (never invents content), or `mediaPolicy: reject` fails fast with a clear diagnosis |

**Example flows**: image analysis → `cortex_execute` on a node with image references (agent mode + read_image/MCP); screenshot/poster generation → Playwright MCP + `artifacts` declaration (magic-byte validated); audio/video processing → only with a media MCP configured (else explicit diagnosis, classified `INPUT_FAILURE`).

**Preferred-model fallback**: when a preferred executor (e.g. a text-only L1 model) is handed an image task, it runs first (attempt is recorded). The executor now **pre-checks modality deterministically** (`modelAcceptsImage` via host `llm.resolveModelInfo`): a model that does not declare image input fails fast with `model lacks image modality` (no generation — a text model must never be allowed to fabricate read-image evidence; observed in production: invented 800x600 / white-pixel result for a 1x1 red PNG). The recovery engine detects the gap and switches directly to a vision-capable candidate — no unnecessary decompose/upgrade round-trip.

**Host prerequisite for vision**: the vision model must declare `inputModalities: [text, image]` in the host's `llm-deepseek.models` entry (e.g. `~/.dsh/settings.yaml`) — otherwise `read_image` refuses with "model does not declare image input" (the catalog default for undeclared entries is `[text]`).

## Cost Model

- **Executor models (sub-models)**: exact `TokenUsage` from subagent/chat sessions (billed = input + cache read/write), priced from the registry — true token accounting.
- **Supervisor (primary model)**: real session-model usage via DSH `sessionProjections`/`tokenMeter` (the `tokenUsage` projection returns `{totals:{uncachedInputTokens, outputTokens, cacheReadTokens, cacheWriteTokens}}`; Cortex normalizes both nested and legacy flat shapes, so `outputTokens` is captured for accurate A-cost — fallback estimate only when no projection exists), plus a "vs direct primary-model run" baseline saving in `cortex_report` (85% cache-hit discounted).
- **Single ledger** (`usage.jsonl`): task cost / global KPI / timeline all derive from usage rows (multi-vote, sub-agent, Gate2 and supervisor calls included); session-level conversation ledger dedupes detail rows across buckets — including across restarts via the `cumulative` anchor (no double-count).
- **Budget pools cover every cost**: supervisor calls map to pools by kind (start/replan→plan, review/fix/evaluate→quality, recover/escalate→emergency), aggregate nodes→exec; the documented **90% high-cost lock is live** (usage ≥90% → new L2/L3 excluded in routing, plus an exec-spend guard).
- **Peak pricing unified**: models.yaml peak windows (×2) apply to A and sub-models alike (`peakPricing` config, default on; Sundays/weekends off-peak).
- UI-triggered evaluations run without a supervisor (chat path) and are **not** counted as supervisor calls.
- **Effective price override** (`cortex_models.price`/`clear_price`, UI, or `/cortex models set-price|clear-price`): a user-set unit price overrides the default, while a model/provider authoritative price wins over both; persisted (survives restarts) and used for routing cost scoring.

## Development

```bash
npm test                 # node --test (engine/service/ui/watchdog unit + smoke) — 292 tests
node tools/verify-post-restart.mjs   # post-restart self-check (7 checks, incl. JSONL integrity + policy refs)
node tools/smoke-ui.mjs              # UI script syntax + SSE + model toggle
```

**Versioning & releases**: the version is read from `package.json`; bumping it (e.g. `npm version patch`) and pushing to `main` — after tests pass — auto-creates an annotated tag `v<version>`, generates a GitHub Release from the git log, and publishes to npm. Pushing the tag is not re-CI'd (no duplicate runs).

## Repository Layout

```
app-pkg/index.js   entry forwarder (rollout cache-bypass, same pattern as dsh-tssdp)
lib/index.js       plugin entry (name/inject/Config/apply + lifecycle)
lib/service.js     CortexService facade (high-level operations behind the tools)
lib/tools.js       13 agent tools
lib/cli.js         /cortex command group
lib/ui-server.js   local web console (127.0.0.1:8788)
lib/watchdog.js    cross-workspace scheduled task injection + goal-loop remediation
lib/watchdog-cli.js /cortex watchdog command handlers
lib/engine/*.js    pure engines (fingerprint/router/budget/quality/recovery/store/executor/kpi/granularity/compute/l0/weight-learn/calibration/peak/state-reset)
config/models.yaml model registry (overridable)
test/              node --test suites
tools/             verification/dev scripts
```

## Feedback & Issues

Found a bug, a misleading description, or a feature you'd like to see? Open an issue on GitHub:

- **Issue tracker**: https://github.com/iguowz/dsh-cortex/issues
- Please include: DSH version, Cortex version (from `/cortex status`), the operation you ran, and the full error/trace output.

Questions, suggestions and feature requests are welcome too.

## License

MIT

Install

dsh plugin --profile web add github:iguowz/dsh-cortex

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source