Metadata-Version: 2.4
Name: dennice
Version: 0.1.14
Summary: A cognitive routing and evaluation harness for data analytics agents.
Author: Keith Fajardo
License: Apache-2.0
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic<3,>=2.7
Requires-Dist: Pillow>=10
Requires-Dist: PyYAML>=6.0
Requires-Dist: textual>=0.70
Requires-Dist: typer<1,>=0.12
Requires-Dist: httpx<1,>=0.27
Requires-Dist: jsonschema<5,>=4.20
Requires-Dist: regex>=2024.11.6
Requires-Dist: mcp<2,>=1.28
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Dynamic: license-file

# Dennice

## The problem Dennice solves

One general prompt does not guide every task well. A data investigation needs evidence. A requirements check needs clear constraints. A conflict needs careful comparison.

Model choice, tool access, and task completion can also be hard to inspect. A response can sound complete even when no independent check supports it.

## What Dennice does

Dennice is a local-first AI harness for analytics and engineering work. It organizes the steps around an AI provider. It does not replace the provider's model.

- **Assess the task.** Identify its task family and main reasoning needs.
- **Add guidance.** Attach short, task-specific instructions to the model prompt.
- **Select a model.** Use a fixed model or choose from an approved pool for the active provider.
- **Set limits.** Apply permission settings and ask for approval when required.
- **Add integrations.** Hooks run commands at named points. The Model Context Protocol (MCP) connects servers that provide tools or context.
- **Check and record.** Run configured completion checks and save a local trace of the task.

Dennice can use a provider's command-line tool or API (application programming interface). It supports Codex, Claude Code, GitHub Copilot, local OpenAI-compatible services, and an offline Mock executor. The selected provider controls the model and may have its own tools and limits.

## How Dennice works

```text
Task and allowed context
        │
        ▼
Task assessment and route selection
        │
        ├──► Optional model and effort selection
        │
        ▼
Reasoning-policy selection and prompt setup
        │
        ▼
Provider executor and permitted tools
        │
        ▼
Completion checks and local run record
```

Dennice calls the assessment stage **System 1**. It calls the execution stage **System 2**. The **router** assesses the task and selects a route. The **executor** sends the task to the selected provider. These names describe software stages. They do not mean that Dennice copies human thought or runs two separate agents.

The assessment stage selects a task family and cognitive demands. The main demand selects one prompt policy. Supporting demands can add a limited number of policies.

In this README, **PA** means **philosophical-assistant guidance**. A PA policy is a short instruction based on a way of reasoning. For example, Socratic guidance asks the model to check assumptions. Empirical guidance asks it to separate evidence from a possible explanation. The policy is part of the model prompt. It is not a separate agent or model. It does not ask for hidden reasoning text.

Harb et al.'s 2026 paper is an inspiration: [“The ballad of LLM agents: philosophical reasoning for chemistry”](https://doi.org/10.1088/2632-2153/ae792d). It appeared in *Machine Learning: Science and Technology*, volume 7, article 030503. The paper studies philosophy-inspired agents for chemistry tasks. Dennice adapts the idea to analytics and engineering. The paper does not test Dennice's task assessment, model routing, or quality and cost results. Dennice needs its own evaluation for those claims.

| Cognitive demand | Guidance |
|---|---|
| `critical_inquiry` | Check assumptions and compare possible explanations |
| `empirical_induction` | Use evidence and measurements; state limits |
| `decomposition` | Split a task into parts that can be checked |
| `constraint_reasoning` | Check requirements and rules |
| `causal_categorization` | Organize entities, causes, and failure types |
| `contradiction_resolution` | Compare conflicting claims or definitions |
| `abstraction` | Identify reusable ideas and structures |

PA policies do not grant access, call tools, select a provider, or prove an answer. They guide the model. They do not guarantee correct output.

## How to use Dennice

### 1. Install Dennice

Dennice requires Python 3.11 or later.

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install dennice
```

On Windows PowerShell:

```powershell
py -m venv .venv
.\.venv\Scripts\Activate.ps1
py -m pip install dennice
```

These commands install the published package from PyPI. To work on Dennice's source code, clone the GitHub repository and install the development dependencies instead:

```bash
git clone https://github.com/keith-fajardo/dennice.git
cd dennice
python -m pip install -e ".[dev]"
```

### 2. Start with the offline setup

```bash
dennice init
dennice
```

`dennice init` creates `dennice.yaml`, benchmark folders, and `.dennice/runs/`. The first setup uses the offline Rule router and Mock executor. The Mock executor returns local test results. It does not contact a model provider.

Type a task in the terminal interface. Press `Ctrl+Enter` to submit it. On Windows, where terminals commonly send that shortcut as a plain Enter, Enter submits and `Shift+Enter` inserts a newline. `Ctrl+J` and **Run** also submit. Use `Ctrl+S` to set the router and executor.

You can also use the command line:

```bash
dennice classify "Why did Snowflake credits increase yesterday?" --json
dennice run "Investigate why Snowflake credits increased yesterday."
dennice benchmark list
dennice benchmark run --mode router --json
```

### 3. Connect a provider when you are ready

Install and sign in to the provider's command-line tool (CLI), or set the API key that you intend to use. Then choose the provider in Setup. See [Configure a provider](#configure-a-provider) for details.

Setup's **Test executor (live)** starts one provider turn. It can use provider quota or credits. The test uses an empty temporary workspace. It stops after 30 seconds, or sooner if you set a lower limit. API requests have a 128-token output limit and one model call. Native CLIs can make internal calls that Dennice cannot count. Usage reports can exceed the 4,096-token stop threshold before Dennice interrupts the turn. Claude's built-in tools are off for this test.

**Test router** contacts the selected router. It does not contact a provider when you select the offline Rule router.

## Configure a provider

The router and executor can use different providers. For example, OpenJev can classify a task while Claude Code executes it.

| Provider | Role | Authentication |
|---|---|---|
| Rule | Offline System 1 router | None |
| Codex | Router or executor | Existing local Codex CLI login; ChatGPT mode by default |
| Jev | Hosted System 1 router | Environment-variable API key |
| OpenJev | Local System 1 router | None; loopback endpoint |
| Claude Code | Executor | Existing Claude Code login |
| GitHub Copilot CLI | Executor | Existing Copilot login |
| OpenAI API / Anthropic API | Executor | Provider API key in environment |
| Local | Executor | Loopback OpenAI-compatible server |
| Mock | Offline executor | None |

Dennice stores names of environment variables. It does not store provider secrets. API adapters use API credentials. The provider bills these credentials separately. CLI adapters use the active login for that provider's CLI. The login can use a subscription or an API key.

### Codex, Claude Code, and Copilot

Install and authenticate the provider’s own CLI before choosing it in Setup. Dennice invokes that local tool and does not collect subscription credentials.

[Codex app-server reports the active account type](https://learn.chatgpt.com/docs/app-server). Before a Codex task or classification, Dennice checks `account/read`. It defaults to ChatGPT authentication. If Codex reports API-key or another provider authentication, Dennice stops before inference. In Setup, select **API key** or **Provider default / other** only when you intend to use that mode. Set `executor.codex_cli_auth` and `router.codex_cli_auth` to `chatgpt`, `api_key`, or `provider_default`. The run trace stores only the executor's authentication mode. This check does not confirm the final billing record.

[Claude Code's authentication guide](https://code.claude.com/docs/en/authentication) says environment variables can select a provider or credential before the saved login. Dennice checks `claude auth status` before each run. By default, it requires a Claude subscription login. API keys, custom endpoints, cloud provider settings, and alternate Anthropic profiles stop the run before inference. In Setup, select **API key** or **Provider default / other** only when you intend to use that method. Set `executor.claude_cli_auth` to `subscription`, `api_key`, or `provider_default`. The last value accepts the CLI's current non-subscription method. Dennice records only the normalized method. It does not save the status output or credentials. This check does not confirm the final billing record.

These adapters target tools on your computer. OpenAI's [app-server guide](https://learn.chatgpt.com/docs/app-server) describes limits on authentication use. Anthropic's [Claude Code guide](https://code.claude.com/docs/en/legal-and-compliance) sets conditions for products that run its binary. Read the [provider integration review](docs/provider-integration-review-2026-10-04.md) before you host or distribute Dennice.

- Codex defaults to a read-only sandbox. Workspace-write must be explicitly selected.
- Claude Code uses a restricted plan profile by default. Its write profile exposes only the allowed file tools, and exact edits require approval.
- Copilot uses a narrow read or file-write allowlist. Every mode exposes Copilot's web search and web-fetch tools for research; the selected provider and your enterprise policy still control their availability. Read-only and Plan mode do not expose its shell tool. Read-write mode exposes its shell tool with file-write tools, so use it only when you want the agent to run project commands. Dennice does not enable MCP tools for the Copilot adapter.
- Copilot uses the user's saved GitHub Copilot CLI login. For GitHub Enterprise Cloud data residency, sign in once outside Dennice with `copilot login --host https://YOUR-ENTERPRISE.ghe.com`. Dennice then invokes that Enterprise Cloud subscription login; it does not require a GitHub.com login or an OpenAI or Anthropic API key. If no Copilot login exists, the CLI may use the signed-in `gh` account.
- Dennice's Copilot picker and `/models` command include its current Copilot CLI model catalog, including `claude-sonnet-5.5`. Enterprise policies, the account plan, the region, and the installed Copilot CLI determine which of those IDs are usable. To see the exact account-enabled list, start the native `copilot` CLI and run its `/models` command.
- Dennice removes `COPILOT_PROVIDER_*`, `COPILOT_MODEL`, and saved BYOK settings from the Copilot process. It gives the CLI an empty temporary provider registry. `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN` can override the saved account. Dennice stops if any of these variables has a value. Unset them before testing.
- Your Enterprise Cloud policy governs Copilot's handling of prompts and outputs. Dennice disables content capture in its local telemetry file, but it cannot change your enterprise's provider policy. Read the [provider integration review](docs/provider-integration-review-2026-10-04.md) before you send workspace content.
- Dennice reads Copilot token totals from a temporary local OpenTelemetry file. Message content capture is off. A budgeted run fails if the CLI does not report valid usage counters. Enterprise-managed OTel settings can override the local file exporter, and some CLI versions do not emit token spans for `copilot -p` runs. In that case Copilot can authenticate and answer, but Dennice stops the run because it cannot honestly enforce the configured token limit. Copilot credits and cost multipliers are not currency. Dennice does not include them in its cost report.

For Enterprise Cloud installations that suppress these counters, Setup offers **Allow unmetered runs** for Copilot. Choose it only when your enterprise accepts that trade-off: Dennice records token and model-call usage as unknown, and cannot enforce those two limits. The run still has the configured elapsed-time limit and a 2 MB response-size safety cap.

Refresh the provider's model list in Setup before you choose a model. Model access, quota, and effort levels depend on your account. Claude model names include the ID returned by its CLI, such as `claude-sonnet-5-5`.

### API and local execution

Set API credentials in the environment before starting Dennice:

```bash
export OPENAI_API_KEY="your-openai-api-key"
export ANTHROPIC_API_KEY="your-anthropic-api-key"
```

Choose the API provider in Setup, refresh its catalog, and select a specific model. For a local provider, enter an OpenAI-compatible `/v1` endpoint, such as:

```text
Ollama:    http://127.0.0.1:11434/v1
LM Studio: http://127.0.0.1:1234/v1
```

API and local execution can use Dennice's tool loop when you run `/tools on`. Local endpoints must use loopback addresses. Dennice sends hosted API keys only to official provider HTTPS hosts. It refuses redirects.

### Local OpenJev router

OpenJev is a local task router. It is not the chat model. It receives the task and typed classification questions. It returns task-family and cognitive-demand scores.

```yaml
router:
  provider: openjev
  model: openjev
openjev:
  endpoint: http://127.0.0.1:8771/v1/systemone
  model: openjev
```

The endpoint must use loopback HTTP or HTTPS. A loopback address sends traffic to the same computer. See the [OpenJev guide](https://huggingface.co/openjev/openjev) for server requirements.

## Automatic model and effort routing

Automatic routing selects only from approved models for the active provider. It does not change the provider, login, permissions, or tool access. The CLI controls whether the active login uses a subscription or API billing. Check the billing method separately.

| Mode | Result |
|---|---|
| `fixed` | Use the configured executor model and effort. |
| `shadow` | Record the recommended route, but use the configured model and effort. |
| `auto` | Run the eligible model and effort from the approved pool. |

The status line shows the configured model and effort. Effort controls the model's reasoning level when the provider supports it. If a run selects different values, `Run route` shows them. After the run, `Last route` shows them. The `Ctx` meter shows the context size reported for that model.

To enable automatic routing, define candidates with their known capabilities. This Codex example must be adapted to models your account supports:

```yaml
routing:
  mode: auto
  model_pinned: false
  effort_pinned: false
  # PA policies attach only when cognitive scores meet these thresholds.
  # Scores are routing signals, not calibrated success probabilities.
  primary_threshold: 0.8
  supporting_threshold: 0.55
  model_pool:
    codex:
      - model: gpt-6-luna
        tier: lightweight
        context_tokens: 32000
        efforts: [low, medium, high]
      - model: gpt-5.6-terra
        tier: strong
        context_tokens: 32000
        efforts: [low, medium, high]
```

The route policy uses low effort for lightweight work, medium effort for balanced work, and high effort for strong work. Simple, low-risk tasks can use a lightweight model. Moderate tasks can use a balanced model. Complex, high-risk, or uncertain tasks can use a strong model. If no model meets the task needs, Auto stops before execution. It does not guess or change providers.

Each candidate must list its context size and tool or image support. Dennice does not infer these values from a model name. Set `model_pinned: true` to keep the current model. Set `effort_pinned: true` to keep the current effort. Auto does not select `xhigh`; choose it manually.

Manage the same settings in the terminal user interface (TUI):

```text
/routing fixed|shadow|auto
/routing pin-model|unpin-model|pin-effort|unpin-effort
/pool add <exact-model-id> lightweight|balanced|strong [tools] [vision] [context=8192] [efforts=low,medium,high]
/pool remove <exact-model-id>
```

Classifier confidence is not a probability of success. The primary score must meet `primary_threshold` before Dennice attaches a PA policy. Each supporting score must meet `supporting_threshold`.

### Research routing

`research_methodology` is a separate cognitive demand. When the router assigns it as the primary demand and its score meets the primary threshold, Dennice attaches a research policy before execution. The policy requires the agent to define the question and scope, choose the permitted source types, assess relevance, authority, recency, and corroboration, distinguish facts from inference, and report material limits.

For web research, the agent uses the executor's permitted web tools and prefers current primary sources. For local research, it inspects the workspace and cites concrete file paths or records. For Confluence or another connected system, it uses only an enabled, approved MCP tool and identifies the page or record it used. The policy cannot enable web access, shell access, or MCP by itself; configure and trust those sources first.

Press `Ctrl+D` during or after a run to inspect both decisions. **Cognitive routing** shows Jev's task family and demand scores. **Model routing** shows the configured provider and model, the selected model and effort, whether Auto applied the change, and the reason recorded by the route policy.

## Use the terminal interface

The terminal interface stores sessions, transcripts, workspace context, and traces in the current project directory.

| Action | Command or shortcut |
|---|---|
| New session | `Ctrl+N` or `/new` |
| Open Setup | `Ctrl+S` |
| Stop active work | `Ctrl+X` |
| Show active configuration | `/config` |
| Switch session | `/session <number>` |
| Search sessions | `/sessions` |
| Rename session | `/rename <title>` |
| List known model IDs | `/models` |
| Choose model | `/model <name>` or Setup |
| Choose effort | `/effort <low|medium|high|xhigh|default>` |
| Choose permissions | `/permissions <read-only|read-write|plan>` |
| Set workspace directory | `/cwd "path"` |
| Attach image | **Attach image** (clipboard), `/attach "/absolute/path/image.png"`, `Ctrl+V` (Windows/Linux), or `⌘V` (macOS) |
| Remove pending images | `/clear-images` |
| Compact earlier context | `/compact` |
| Start a bounded goal | `/goal <objective>` |
| Inspect recovery | `/recovery list` |

The task box accepts multiple lines. Press `Ctrl+Enter` to submit a task. Some Windows terminals collapse that shortcut into a plain Enter, so Dennice keeps Enter for a newline and provides `Ctrl+J` and **Run** as submission fallbacks. Start a local terminal command with `!`, for example `! git status --short`. Dennice shows the command output. It does not add that output to the model conversation.

### Sessions, workspace files, and images

Sessions remain after restart in the same workspace. Session search ignores letter case. It accepts regular expressions, such as `snowflake|billing`. Each session has its own workspace directory.

The file explorer can search, preview, save, undo, redo, and replace text. Search has size and count limits. It skips links, credential-like files, binary files, and large files. You must confirm file changes. Dennice does not silently overwrite many files. Secure file access uses POSIX features. On Windows, use WSL. Native Windows file editing stops when it cannot enforce these checks.

You can attach up to eight images. Each image can be a PNG, JPEG, GIF, or WebP file. Each file can be up to 10 MB. Clipboard images are saved in `.dennice/attachments/`. Dennice does not send them until you submit a task. Codex receives image attachments. Claude Code receives an instruction to read the image file. API and local providers receive image content when supported. The router receives text, not image pixels.

### Skills

Use `/skills` to list local Claude and Codex skills. Use `/skill <qualified-key> <task>` to run a skill. Skill text is user-level context. It cannot grant access, run scripts automatically, or bypass approval.

## Hooks and MCP

Dennice has its own hooks and MCP connector. A hook is a command that runs at a named point, such as before execution. MCP lets a compatible server provide tools, data resources, or prompt templates. These features do not replace extensions built into Claude Code or other providers.

Supported hook events are `before_route`, `after_route`, `before_execution`, `before_tool`, `after_tool`, `before_verification`, and `turn_complete`. A hook receives limited task metadata. It can allow or deny the related harness action. It cannot grant access, change pinned routes, or intercept every action inside a provider's tools.

MCP is available to API and local tool loops. Dennice does not add it to native Codex, Claude Code, or Copilot loops. You must allow each MCP tool, resource, or prompt. Each access requires approval. Dennice treats MCP content as untrusted data, not as system instructions.

Tools, hooks, and MCP are disabled by default:

```yaml
tools:
  enabled: false
  root: .
hooks:
  - name: validate
    event: before_execution
    command: [python, scripts/validate.py]
    enabled: false
    required: true
mcp:
  - name: example
    transport: stdio
    command: [python, scripts/mcp_server.py]
    enabled: false
    approved_tools: [lookup]
```

Use `/tools on`, `/hooks list|trust|enable|disable <name>`, and `/mcp list|trust|enable|disable|test <name>`. Trust applies to the current app launch and workspace. A change to server settings removes that trust. Opening Setup does not start a process.

## Verification, traces, and recovery

Dennice saves run data in `.dennice/runs/runs.sqlite3` by default. A run record can include the task, configuration, route, PA policies, approvals, tool events, usage, output, and verification result.

```bash
dennice inspect <run-id>
```

`dennice run` returns an error status for failed, timed-out, cancelled, or interrupted runs. It labels partial output as unverified. `dennice inspect` shows the stop reason. Add `--json` to view the full trace.

When a provider CLI fails, Dennice records its exit status or a short error category. It does not save raw provider error text. That text can contain prompts or credentials. Check the provider CLI on your computer for more detail.

Run data can contain prompts, transcripts, image paths, configuration details, and output as plain text. Protect the runs directory. File permissions do not encrypt its contents.

Dennice does not repeat interrupted work automatically. An external action may already have happened. Use `/recovery inspect <run-id>` to inspect it. Use `/recovery reconcile <run-id> <operation-id> <completed|not_executed|compensated> <evidence>` to record a checked result.

Goals add a task objective and a retry limit:

```text
/goal Verify the dashboard query against fixture data
```

Set completion checks before you start a goal:

```yaml
verification:
  required_files: [report.md]
  commands:
    - [python, -m, pytest, tests/test_report.py]
```

An answer is `unverified` until an independent file or command check passes. Verification commands require approval. Dennice does not sandbox these commands. Budgets can limit run time, model calls, tool calls, output tokens, and reported total tokens. The provider may not report all usage.

For Codex, `budgets.max_total_tokens` defaults to `100000`. It counts reported input and output tokens for the full run. The status line shows a `Run` meter. After the run, it shows `Last run`. `≥` means some usage is unknown. `pending` and `unknown` mean no usable usage report has arrived. `Ctx` shows the latest model request against the context limit. It does not show the remaining run budget. Codex reports usage after model activity. A run can exceed its limit before Dennice stops it. Raise the limit in `dennice.yaml` only when needed:

```yaml
budgets:
  max_total_tokens: 200000
```

API, Claude, Codex, and Copilot runs fail when required token counts are missing. Copilot reports usage after its CLI exits. Dennice can report that the run exceeded its budget. It cannot stop an internal model call at the exact token limit. Copilot usage comes from a temporary local OpenTelemetry file. Dennice turns off prompt and response capture.

## Privacy and operational boundaries

- The router cannot choose a provider, grant permission, execute a tool, or create arbitrary routes.
- Codex classification runs its CLI in a disposable directory with a read-only sandbox; it receives the task text and opt-in routing history, not the project working directory.
- Auto-routing stays within the active provider’s approved pool.
- Set `privacy.router_history: true` before prior conversation turns are shared with the router.
- `privacy.local_only: true` rejects remote/CLI providers and unsandboxed hooks or MCP processes. It does not sandbox arbitrary local processes.
- Hosted routers reject redirects and implicit proxies; OpenJev accepts loopback endpoints only.
- Cancelling stops ongoing work but cannot undo an external side effect.

Review the selected provider, model, permission profile, tool settings, and workspace directory before authorizing work with side effects.

## Known limits

- The Rule router is a narrow deterministic development classifier. Use Codex, Jev, or OpenJev for broader task classification.
- The Rule router lacks a full assessment for most tasks, so automatic routing treats them conservatively.
- OpenJev’s current typed request does not ask whether tools or vision are needed. Attached images are still detected by the route policy.
- Cognitive scores are uncalibrated, so PA thresholds need held-out evaluation before they can be treated as quality controls.
- Model capability declarations, context sizes, and effort support must be verified with the provider and account.
- Current benchmarks measure routing labels, not general task quality, cost savings, or provider parity.
- Provider-native sessions and tools remain provider-specific. Dennice cannot intercept every action inside a native provider loop.
- Full platform qualification, held-out routing evaluations, and some provider integration evidence remain release gates.

See the [production plan](docs/production-harness-plan.md) and [recovery guide](docs/recovery-and-accounting.md). The [platform](docs/platform-and-evaluation.md), [extension](docs/extension-qualification.md), and [provider](docs/provider-integration-review-2026-10-04.md) reviews explain limits and release checks.

## Develop and test

```bash
pytest -q
ruff check src tests
```

The Snowflake benchmark uses synthetic development data. `dennice init` copies three evidence files into `benchmarks/fixtures/`. Dennice checks each file path and size before a model call. It passes the data as untrusted task content. It does not add the answer key or task labels to the prompt. This benchmark scores routing labels only. Use representative tasks and independent checks to evaluate task success, PA policies, model choice, cost, or speed.

## Windows notes

The terminal interface works in Windows terminals. To use Codex, Claude Code, or Copilot, install and sign in to its CLI. Run Dennice from Git Bash or WSL. Make sure `bash` is on `PATH`. Dennice uses Bash to start these CLIs on Windows. Because some Windows terminals cannot distinguish `Ctrl+Enter` from Enter, Dennice treats Enter as submit on Windows. Use `Shift+Enter` for a newline, or use `Ctrl+J` or **Run** to submit.

Claude Code supports Windows through WSL or Git for Windows. Install GitHub Copilot CLI with `npm install -g @github/copilot`. Sign in with `copilot login`. Your account or organization controls provider access.
