Skip to content
Open
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
9 changes: 9 additions & 0 deletions .context/AGENT_PLAYBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ go run ./cmd/ctx # ✗ avoid unless developing ctx itself
```
Check with `which ctx` if unsure whether it's installed.

### Optional AI Backends

`ctx ai` is optional and fail-closed. Use `ctx setup --backend <name>` to
configure a backend, `ctx ai ping` to verify it, and `ctx ai propose <input>
--emit ...` only to write reviewable artifacts under `.context/proposals/ai/`.
Do not wire deterministic commands, ceremonies, or hooks to backend
availability; `ctx status`, `ctx agent`, and hooks must keep working with no
backend configured.

### When ctx Returns an Error

Triage the error before reacting:
Expand Down
47 changes: 46 additions & 1 deletion .context/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- INDEX:START -->
| Date | Decision |
|----|--------|
| 2026-06-19 | `ctx ai` is a separate namespace with proposed-patch output only |
| 2026-06-07 | ctx-dream executor is a documented contract, not a hardcoded cron/claude assumption |
| 2026-06-07 | Output belongs in write/ — taxonomy and emission style (consolidated) |
| 2026-06-07 | Package taxonomy and shared-code placement (consolidated) |
Expand Down Expand Up @@ -107,6 +108,51 @@ For significant decisions:

-->

## [2026-06-19-064500] `ctx ai` is a separate namespace with proposed-patch output only

**Status**: Accepted

**Context**: GitHub issue #92 (`ctx ai backend`) introduces an optional,
local-first AI backend layer. The governing spec left several Block A choices
open: whether AI use should live under a new `ctx ai <verb>` namespace or as
flags on existing commands, where the validation consumer should write
proposals, whether Block A needs a companion skill, and how to reconcile the
spec's TOML examples with the repo's existing YAML `.ctxrc` parser.

**Decision**: Block A uses a new top-level `ctx ai <verb>` namespace. Backend
configuration uses the existing YAML `.ctxrc` shape under `backends:` rather
than TOML-style `[backends]` tables. `ctx setup --backend <name>` is a distinct
setup mode that can run without the current `<tool>` positional argument. The
provisional proposal queue is `.context/proposals/ai/`, and the Block A
validation consumer is `ctx ai propose <input> --emit ...`, a generic
validation-only proposer that writes proposed-patch JSON artifacts and never
mutates `.context/*.md`. No new companion skill ships in Block A; command
assets, setup docs, the `ctx ai` CLI reference, the vLLM recipe, and the agent
playbook note cover the user-facing surface.

**Rationale**: A separate `ctx ai` namespace keeps optional AI behavior out of
deterministic commands (`ctx status`, `ctx agent`, ceremonies, and hooks), makes
fail-closed behavior explicit, and avoids smuggling backend availability into
existing deterministic verbs through flags like `--use-ai`. YAML config matches
the actual `internal/rc` implementation and avoids landing a spec that cannot
be implemented without replacing the config parser. `.context/proposals/ai/`
keeps AI-produced suggestions inside the cognitive substrate while preserving
the human gate before canonical memory changes. A generic `propose` verb proves
backend dispatch and artifact writing without pretending to settle the final
Block B taxonomy; later `ctx ai compact` or `ctx ai ingest` commands remain
available once the extraction-and-recall spec is promoted.

**Consequence**: Implementations must add a deterministic-boundary guard so
agent/status/ceremony paths cannot import `internal/backend` or invoke `ctx ai`.
Multiple configured backends require `--backend <name>` or `backends.default`;
there is no implicit selection and no deterministic fallback. Proposed-patch
artifacts need a minimal schema with backend, model, input reference, emit
kinds, proposed rows, source spans or citations when available, and status
metadata. Documentation and command assets are part of the same deliverable
because `ctx ai` is a user-facing surface. Spec: `specs/ctx-ai-backend.md`.

---

## [2026-06-07-112203] ctx-dream executor is a documented contract, not a hardcoded cron/claude assumption

**Status**: Accepted
Expand Down Expand Up @@ -1300,4 +1346,3 @@ inherits it, and cleanup is automatic at test end. One line replaces the helper.
to maintain. Pattern reusable for other subprocess tests.

---

175 changes: 175 additions & 0 deletions .context/TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,181 @@ TASK STATUS LABELS:
`--phase` flag too, and we can have a auditor/normalizer for the current
task document; or a skill that does a semantic pass, or both too.

## Phase AI-A: `ctx ai` Backend Foundation

Spec: `specs/ctx-ai-backend.md`. Read the spec before starting any AI-A task.
Tracks GitHub issue #92.

- [x] Decide the AI command CLI namespace: `ctx ai <verb>` (new top-level)
vs. flags on existing commands (`--use-ai`, `--emit`, etc.). Record the
call as a `.context/DECISIONS.md` entry naming the chosen shape and the
rejected alternative with rationale. Blocks every other task in this group.
Spec: `specs/ctx-ai-backend.md` Open Question #1. #priority:medium
#added:2026-06-19 #completed:2026-06-19

- [x] Implement the backend contract and registry: new `internal/backend/`
package with `Backend` interface (`Name`, `Ping`, `Complete`),
`Request`/`Response` types, and a `Registry` (`Register`, `Resolve`,
`Default`). No per-backend implementations yet; this is the abstraction
surface that later tasks plug into. Unit tests cover single, multiple,
default, and missing backend resolution. Spec: `specs/ctx-ai-backend.md`
§Implementation. #priority:medium #added:2026-06-19
#completed:2026-06-19
Shipped: added `internal/backend/` with zero-value-safe registry, public
`SetDefault`, `Register`, `Resolve`, and `Default`; `Config`, `Request`,
`Response`, `Backend`, and `Factory` types; typed errors under
`internal/err/backend`; and structural error text constants under
`internal/config/backend`. Tests cover single default resolution, ambiguous
multiple-backend default, explicit default, missing default, empty registry,
missing backend, duplicate registration, and factory-error wrapping. Verified:
`go test ./internal/backend ./internal/err/backend ./internal/config/backend`,
`go test ./internal/audit`, and `git diff --check`.

- [x] Extend `internal/rc/` to parse and validate the `.ctxrc` `backends:`
YAML mapping per the spec's Configuration section: per-backend `endpoint`,
`api_key_env`, `timeout`, `default_model`, plus optional
`backends.default`. Refuse malformed mappings with a clear parse error
naming the offending key. Add fixtures and round-trip tests. Spec:
`specs/ctx-ai-backend.md` §Configuration. #priority:medium
#added:2026-06-19
#completed:2026-06-19
Shipped: added `BackendsRC` / `BackendRC` parsing for mixed YAML mapping shape
(`backends.default` plus named backend definitions), strict backend-field
decoding, semantic validation for missing endpoint and default references,
and config constants for backend rc keys/messages. Multiple backends without a
default intentionally parse successfully because dispatch owns that error.
Tests cover well-formed config, missing endpoint, malformed shape, missing
default target, multiple without default, unknown nested fields, and empty
backends. Verified: `go test ./internal/rc ./internal/audit`,
`go test ./internal/backend ./internal/err/backend ./internal/config/backend`,
and `git diff --check`.

- [x] Implement the minimum viable backend set: `vllm` (canonical local) and
generic `openai-compatible` (the contract floor) in
`internal/backend/vllm.go` and `internal/backend/openaicompat.go`. Both must
implement `Ping` (HTTP GET on `/v1/models`) and `Complete` (POST
`/v1/chat/completions`). Fail closed on unreachable, 4xx, 5xx, and timeout;
never retry with a different model and never fall back to deterministic
behavior. Spec: `specs/ctx-ai-backend.md` §Approach and §Edge Cases.
#priority:medium #added:2026-06-19
#completed:2026-06-19
Shipped: added generic OpenAI-compatible HTTP backend and vLLM wrapper over the
same contract. `Ping` calls `/v1/models`; `Complete` posts to
`/v1/chat/completions`, applies default model fallback / request model
override, optionally reads `api_key_env` for a bearer token, validates HTTP(S)
endpoints, uses configured timeout with a safe default, and fails closed on
transport, timeout, 4xx, 5xx, decode, and request errors. Tests cover ping,
completion, upstream body propagation, unreachable server, timeout, invalid
endpoint scheme, model fallback/override, auth header, and vLLM naming. Factory
functions remain private until a real cross-package caller lands, per the dead
export audit. Verified: `go test ./internal/backend ./internal/err/backend
./internal/config/backend ./internal/rc ./internal/audit` and
`git diff --check`.

- [x] Add the named-backend implementations: `openai`, `anthropic`, `ollama`,
`lmstudio` in `internal/backend/`. Each is a thin wrapper over
`openaicompat` with backend-specific defaults (endpoint, auth header shape,
env-var name). Anthropic uses the Messages API endpoint where supported but
inherits the OpenAI-compatible floor for `/v1/chat/completions`. Spec:
`specs/ctx-ai-backend.md` §Approach. #priority:medium #added:2026-06-19
#completed:2026-06-19
Shipped: added unexported named factories for `openai`, `anthropic`, `ollama`,
`lmstudio`, plus vLLM default endpoint handling. Each factory returns the
OpenAI-compatible implementation with backend-specific name, default endpoint,
and default API key env var where applicable. Anthropic is explicitly a floor
implementation for now; Messages API specialization waits for capability
detection. Factories remain private until real registry wiring lands to avoid
dead exports. Tests cover each factory's name/default behavior and preservation
of configured endpoint/env overrides. Verified: `go test ./internal/backend
./internal/config/backend ./internal/err/backend ./internal/audit`,
`go test ./internal/rc`, and `git diff --check`.

- [x] Extend the `ctx setup` family with `--backend <name>` as a distinct setup
mode that can run without the existing `<tool>` positional argument:
templates endpoint + auth wiring into `.ctxrc` and, where applicable,
downstream AI-tool configs (`ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`). Honour
existing env-var values: warn but do not overwrite. Lives in new
`internal/cli/setup/core/backend/` subpackage. Spec:
`specs/ctx-ai-backend.md` §Implementation. #priority:medium
#added:2026-06-19
#completed:2026-06-19
Shipped: `ctx setup --backend <name>` now runs without a positional tool,
supports dry-run YAML output, and writes/merges `.ctxrc` with `--write` while
preserving unrelated YAML fields. Added `--endpoint`, `--api-key-env`,
`--model`, and `--timeout` setup flags; backend name validation; backend mode
precedence when a positional tool is also present; default endpoint/env values;
and env-var conflict warnings. Tests cover no-arg backend mode, missing backend
rejection, existing tool compatibility, backend-mode precedence, unsupported
backend rejection, dry-run output, `.ctxrc` creation, unrelated-field
preservation, and env warning. Verified: `go test ./internal/cli/setup/...
./internal/rc ./internal/backend ./internal/audit` and `git diff --check`.

- [x] Build the `ctx ai` command surface. Minimum verbs: `ping` (reachability +
first model listed) plus `propose` as the Block A validation-only generic
proposer. All AI commands honour `--backend` flag (falling back to
`backends.default`), fail closed when no backend is configured, fail closed
when no backend is reachable, require explicit selection when multiple
backends are configured without a default, and surface upstream errors
verbatim. Spec: `specs/ctx-ai-backend.md` §Interface. #priority:medium
#added:2026-06-19
#completed:2026-06-19
Shipped: added the `ctx ai` command group with `ping` and `propose`, backend
dispatch through `.ctxrc` `backends:`, `--backend` selection, fail-closed empty
and ambiguous backend handling, built-in backend registration, and command / flag
assets. `ctx ai ping` reports the resolved backend, defaulted endpoint, and
first listed model from `/v1/models`. Verified: `go test ./internal/cli/ai/...
./internal/backend ./internal/rc ./internal/audit ./internal/compliance` and
`git diff --check`.

- [x] Add the deterministic-core boundary guard: a unit test or lint check that
fails if `internal/cli/agent/`, `internal/cli/status/`, or any
deterministic-ceremony hook imports or invokes `internal/backend/` or `ctx ai`.
This structurally enforces that `ctx status`, `ctx agent`, ceremonies, and
hooks remain additive-only and keep working with no backend configured. Spec:
`specs/ctx-ai-backend.md` §Validation Rules and §Testing. #priority:medium
#added:2026-06-19
#completed:2026-06-19
Shipped: added `internal/compliance/ai_boundary_test.go`, which scans
non-test Go files under `internal/cli/agent/`, `internal/cli/status/`, and
`internal/cli/hook/` and fails on `internal/backend` imports or `ctx ai`
invocation/documentation. Verified: `go test ./internal/compliance
./internal/audit`.

- [x] Ship the Block A validation consumer: `ctx ai propose <input> --emit
decisions,learnings,tasks,open-questions`. This is a validation-only generic
proposer and must not foreclose later `ctx ai compact` or `ctx ai ingest`
command taxonomy. It performs schema-constrained dispatch through the backend,
validates JSON, and writes one proposed-patch JSON artifact to
`.context/proposals/ai/` with backend, model, input reference, emit kinds,
proposed rows, source spans/citations when available, and status metadata.
It must never directly mutate `.context/*.md`. Integration test confirms the
round-trip against a fake OpenAI-compatible `httptest` server and confirms
`.context/*.md` files are unchanged. Spec: `specs/ctx-ai-backend.md` §Testing
and Open Question #5. #priority:medium #added:2026-06-19
#completed:2026-06-19
Shipped: `ctx ai propose` reads a user input file, sends a schema-constrained
JSON request through the selected backend, validates the response as JSON, and
writes one proposed-patch artifact under `.context/proposals/ai/` with backend,
model, input reference, emit kinds, status, and decoded response payload. Tests
confirm the fake OpenAI-compatible round-trip and that `.context/*.md` remains
unchanged. Verified with the Phase 6 command-surface test set above.

- [x] Write the documentation deliverables: one new recipe
(`docs/recipes/local-inference-with-vllm.md` or
`docs/recipes/ai-backend-setup.md`) covering the
`ctx setup --backend vllm` flow end-to-end, plus a CLI reference page under
`docs/cli/` for `ctx ai`. Also update command assets/examples and the agent
playbook note listed in the spec. The recipe is one file, not a recipe-surface
rework. Spec: `specs/ctx-ai-backend.md` §Non-Goals. #priority:medium
#added:2026-06-19
#completed:2026-06-19
Shipped: added `docs/cli/ai.md`, updated `docs/cli/setup.md`, added `ctx ai`
and `backends:` coverage to `docs/cli/index.md`, added
`docs/recipes/local-inference-with-vllm.md` and linked it from the recipes
index, and documented optional/fail-closed AI backend usage in
`.context/AGENT_PLAYBOOK.md`. Verified: `go test ./internal/audit
./internal/compliance`.

## Phase CLI-FIX: CLI Infrastructure Fixes

These have priority because other knowledge ingestion projects depend on them.
Expand Down
16 changes: 16 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ linters:
- linters: [gosec]
text: "G101"
path: "internal/config/embed/text/"
# FlagDescKey constants are CLI flag description keys, not credentials
- linters: [gosec]
text: "G101"
path: "internal/config/embed/flag/"
# Flag name constants are CLI flag identifiers, not credentials
- linters: [gosec]
text: "G101"
path: "internal/config/flag/"
# RC key constants are YAML config key names, not credentials
- linters: [gosec]
text: "G101"
path: "internal/config/rc/"
# Default env var name constants are identifiers, not credentials
- linters: [gosec]
text: "G101"
path: "internal/config/backend/"

run:
timeout: 5m
Expand Down
58 changes: 58 additions & 0 deletions docs/cli/ai.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
# / ctx: https://ctx.ist
# ,'`./ do you remember?
# `.,'\
# \ Copyright 2026-present Context contributors.
# SPDX-License-Identifier: Apache-2.0

title: AI Backends
icon: lucide/brain-circuit
---

![ctx](../images/ctx-banner.png)

## `ctx ai`

Optional AI backend commands. These commands are additive: deterministic
commands such as `ctx status`, `ctx agent`, and hooks do not require a backend.

Configure a backend first:

```bash
ctx setup --backend vllm --endpoint http://localhost:8000 --write
```

### `ctx ai ping`

Check the selected backend by reading `/v1/models`.

```bash
ctx ai ping [--backend <name>]
```

Output includes the resolved backend name, endpoint, and first model listed.

### `ctx ai propose`

Send an input file to the selected backend and write a reviewable proposal
artifact. It never edits `.context/*.md` directly.

```bash
ctx ai propose <input> --emit decisions,learnings,tasks,open-questions \
[--backend <name>]
```

Artifacts are written under `.context/proposals/ai/` as JSON proposed-patch
records with backend, model, input, emit kinds, status, and the decoded response.

### Backend selection

`ctx ai` uses this order:

1. `--backend <name>`
2. `.ctxrc` `backends.default`
3. the only configured backend, if exactly one exists

If multiple backends exist and none is selected, the command fails closed.
If no backend is configured or the backend is unreachable, the command fails
closed; non-AI commands are unaffected.
Loading
Loading