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
131 changes: 83 additions & 48 deletions docs/core-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,64 @@ sidebar_position: 3

# Core Concepts

NeatContext assembles the context an LLM uses from four building blocks, and
scopes that context **per chat tab**. This page explains each piece and how they
combine. (Each has a full [feature page](/category/features) as well.)
NeatContext organizes the context an AI client uses, scopes it **per Context
workspace**, and hands it off over a local MCP connection — **without running a
model of its own**. This page explains each piece and how they combine. (Each has
a full [feature page](/category/features) as well.)

## The chat tab is the unit of context
## NeatContext runs no model

Every chat lives in its own **tab**, and each tab carries its own:
This is the idea everything else follows from. NeatContext does **not** host a
chat, does **not** call a model, and does **not** store a model API key. It is a
**control center**: you curate context in it, and your existing AI client — Claude
Code, Claude Desktop, Codex CLI, or ChatGPT Desktop — does the reading,
searching, tool-calling, and answer-writing with its own model.

1. attached **domain profiles** (one of them **active**),
2. attached **knowledge folders**,
When you connect a client, NeatContext exposes a small, read-only local MCP
server. The client calls **`get_context`** and receives **pointers, not content**:

while sharing the workspace-wide pieces:
- the **domain profile file paths** to read,
- the **knowledge folder paths** to search, and
- the **extension tools** available on this connection.

3. enabled **extensions**, and
4. your configured **model**.
The client then reads those files, searches those folders, and calls those tools
itself. NeatContext never uploads your corpus and never sees the client's model.

When you ask a question, NeatContext gives the model the tab's active profile as
steering context, searches the tab's knowledge folders for grounded evidence, and
offers the enabled extensions' tools so the model can query your real systems.
## The Library holds reusable resources

Because context is per-tab, changing it never means swapping things in and out:
keep *Team A's* profile and runbooks in one tab and *Team B's* in another, and
flip between them. Same tools, same data, different reasoning.
The **[Library](./features/library.md)** is your local registry of reusable
resources:

![Two tabs, each with its own team context](/img/features/chat-tabs.png)
- **Domain profiles** — Markdown files you create in-app or **link in place**
from disk.
- **Knowledge folders** — local folders you link in place.
- **Extensions** — read-only tool connectors (bundled, personally added, or from
a shared team Library).

A Library resource can be selected by many Contexts. Removing it from a Context
never deletes it from the Library or from disk. An optional **read-only Team
Library** — any folder following the `profiles/` + `knowledge/` + `extensions/`
convention (typically a git clone) — lets a team share approved resources.

## The Context is the unit of handoff

A **[Context](./features/contexts.md)** is a named workspace for one operational
scope, shown as a **tab**. Each Context selects its own:

1. **domain profiles** (one of them **active**),
2. **knowledge folders**, and
3. enabled **extensions**.

Because context is per-Context, you never swap things in and out: keep *Team A's*
profile and runbooks in one Context tab and *Team B's* in another, and connect a
client to whichever you need. Every AI-client session is pinned to exactly one
Context.

## Domain profiles

A **domain profile** is a Markdown file describing a team or domain: what it
owns, how it investigates, and the actions it must not take. The active profile
steers the model toward *that* team's correct behavior.
owns, how it investigates, and the actions it must not take. The connected client
reads the active profile completely and treats it as its primary behavioral guide.

Profiles use YAML front matter for metadata, followed by free-form Markdown:

Expand Down Expand Up @@ -70,21 +97,23 @@ Profiles are plain Markdown you own and version however you like.
## Knowledge bases

A **knowledge base** is a local folder of documents — typically a team's
**runbooks**, **troubleshooting guides (TSGs)**, and **postmortems**. NeatContext
searches attached folders — in place, locally on your machine — to ground answers
in your material, and cites the documents it used as **clickable sources** under
the answer.
**runbooks**, **troubleshooting guides (TSGs)**, and **postmortems**. The
connected AI client searches the attached folders — in place, locally on your
machine — to ground its answer, and cites the documents it used as **clickable
`file://` sources** at the end of the answer.

Because a knowledge base is just a folder on disk, you keep it in whatever repo
you already use. Non-content directories (`.git`, `node_modules`, build outputs)
are skipped automatically.
you already use.
→ Full details: [Knowledge Bases](./features/knowledge-bases.md)

## Extensions

An **extension** is a connector that gives the model **tools** for your real
systems — read an incident, search logs, list deployments. Each one runs locally
as part of NeatContext, and the model's tool use is always visible in the chat.
An **extension** is a read-only connector that gives your AI **tools** for your
real systems — read an incident, search logs, list deployments. Each one is a
local stdio MCP server; when a client is connected, NeatContext advertises the
selected extension's tools on the same connection and **proxies** each call,
injecting the extension's credentials from your OS keychain so the client never
sees a secret.

Extensions declare how they authenticate, which determines the Connect
experience: nothing to configure, an inline **API-key form** (the bundled
Expand All @@ -93,31 +122,37 @@ encrypted with your OS secure storage and stay on your machine.
→ Using them: [Using Extensions](./features/using-extensions.md) ·
Building them: [Building Extensions](./extensions/overview.md)

## Your model
## AI clients

NeatContext does **not** provide hosted inference. You configure your own
OpenAI-compatible endpoint (cloud or local) with a base URL, model name, and API
key; requests go directly from your machine to it. To use extension tools, the
model must be **tool-calling capable**.
→ Full details: [Model Provider](./features/model-provider.md)
You connect one of the supported clients — **Claude Code**, **Claude Desktop**,
**Codex CLI**, or **ChatGPT Desktop** — from the Context page. NeatContext opens
a **fresh, Context-pinned session** with an invocation-scoped or project-scoped
MCP configuration; it never rewrites your global client config. The client brings
its own model.
→ Full details: [Connecting AI Clients](./features/connect-ai-clients.md)

## How it all fits together

```text
┌────────────────────────── Chat tab ──────────────────────────┐
│ │
Question │ Active profile + Knowledge folders + Extensions │
──────► (how to reason) (what to cite) (tools to call) │
│ \ | / │
│ ▼ ▼ ▼ │
│ Your configured model │
│ │ │
└────────────────────────────┼─────────────────────────────────┘
Grounded, team-specific, cited answer
┌───────────────────── One Context workspace ──────────────────────┐
│ │
│ Active profile + Knowledge folders + Extensions │
│ (how to reason) (what to cite) (tools to call) │
└──────────────────────────────┬───────────────────────────────────┘
│ Connect (local MCP)
Your AI client — Claude Code / Claude Desktop /
Codex CLI / ChatGPT Desktop
get_context → reads files, searches folders, calls tools
Grounded, team-specific answer with a ## Sources footer
```

Edits you make to a connected Context are picked up on the client's **next**
`get_context` call — no reconnect needed. Selecting a different Context tab does
**not** retarget an open session; connect again to open a new session for it.

The [Incident Analysis walkthrough](./guides/incident-analysis.md) shows this in
action: the same incident and the same tools in two tabs, with two different
profiles and knowledge bases, produce two different — and both correct —
outcomes.
action: the same incident and the same tools in two Contexts, with two different
profiles and knowledge bases, produce two different — and both correct — outcomes.
2 changes: 1 addition & 1 deletion docs/extensions/_category_.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"position": 6,
"link": {
"type": "generated-index",
"description": "Write connectors that give the model tools for your own systems, using the Model Context Protocol (MCP)."
"description": "Write connectors that give your AI client tools for your own systems, using the Model Context Protocol (MCP)."
}
}
14 changes: 8 additions & 6 deletions docs/extensions/api-key-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ async function searchLogs(args) {
if (!query) throw new Error('Tool argument "query" is required.');

// 1. Not connected: no handshake arrived. Return a connection-required
// result — NeatContext stops the tool loop, answers the user with your
// message, and offers a "Connect Acme Logs" button in the chat.
// result — the loop stops and the connected AI client relays your
// message as a "connect Acme Logs first" prompt.
if (!connection || !connection.apiKey) {
return {
error: "acme_logs_not_connected",
Expand Down Expand Up @@ -225,14 +225,16 @@ don't include them in tool results, and redact them from anything you append to

## 5. Test it

1. **Extensions → Add extension**, select your `acme-logs/` folder, **Enable** it.
1. **Extensions → Add extension**, select your `acme-logs/` folder, **Enable** it,
and select it into a Context.
2. Click **Connect** with the form empty → the inline "API key is required."
error appears and nothing is saved.
3. Ask the model something that triggers your tool *before connecting* → the
answer should be your `message` with a **Connect Acme Logs** button.
3. Connect your AI client and ask something that triggers your tool *before
connecting the extension* → the answer should relay your `message` telling you
to connect Acme Logs first.
4. Fill the form, **Connect**, ask again → the tool should call your backend with
the key.
5. Enter a wrong key, ask again → the access-denied message and Connect button.
5. Enter a wrong key, ask again → the access-denied message appears.

## Field cheat sheet

Expand Down
9 changes: 5 additions & 4 deletions docs/extensions/building-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,12 @@ descriptions:
1. In NeatContext, open **Extensions → Add extension** and select your
`status-board/` folder.
2. **Enable** it. With `connection: none` there's nothing to authenticate.
3. In a chat with a tool-calling model, ask: *"Is checkout-api healthy right now?"*
The model should call `board_get_service_status` and answer from the result.
3. Select the extension into a Context, connect your AI client, and ask:
*"Is checkout-api healthy right now?"* The client should call
`board_get_service_status` and answer from the result.

If a tool doesn't get called, check that your model is tool-calling capable, that
`tools/list` returns the tool, and that the description makes its purpose obvious.
If a tool doesn't get called, check that `tools/list` returns the tool and that its
description makes its purpose obvious.

## 6. Point it at real systems

Expand Down
9 changes: 5 additions & 4 deletions docs/extensions/create-extension-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ tracker, or any other JSON-over-HTTP service.

## Open the builder

On the **Extensions** page (top bar → Extensions), click **Create**. The
On the **Extensions** page, click **Create**. The
builder opens with a step indicator: **Basics → Auth → Data → Review**. Each
step validates when you click **Next**, so mistakes surface next to the field
that caused them — the same checks the app applies when it generates the
Expand All @@ -42,7 +42,7 @@ extension.

| Field | What to enter |
|---|---|
| **Extension name** | A display name, e.g. `GitHub Users`. Shown on the Extensions page and in the chat activity trace; also becomes the generated folder's name (`github-users`). No effect on API calls. |
| **Extension name** | A display name, e.g. `GitHub Users`. Shown on the Extensions page and in the Context activity log when the tool runs; also becomes the generated folder's name (`github-users`). No effect on API calls. |
| **Base URL** | The address of the API: scheme + host, plus an optional path prefix — `https://api.github.com`, or e.g. `https://api.example.com/v2`. Every tool call requests **Base URL + Endpoint path** (Step 3). Must be http(s); a trailing slash is removed for you. |
| **Description** | Optional. A short note shown on the extension's card, e.g. `Look up GitHub user profiles`. |

Expand Down Expand Up @@ -125,11 +125,12 @@ card enabled.

1. If the extension needs credentials, fill the **Connect** form (API key) or
click **Connect** (OAuth) on its card.
2. Ask something in chat that needs the tool:
2. Select the extension into a Context, connect your AI client, and ask something
that needs the tool:

> What company does the GitHub user torvalds work for?

The activity trace shows `github_get_user` running, and the answer comes
The Context's activity log shows `github_get_user` running, and the answer comes
from the live API response.

## Growing beyond the builder
Expand Down
2 changes: 1 addition & 1 deletion docs/extensions/manifest-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ model retry:

| Result shape | Effect |
|---|---|
| `{ "connection_required": true, "provider": "<id>", "message": "…" }` (plus your own `error` code) | Loop stops; `message` becomes the answer; a **Connect &lt;Extension&gt;** button is offered in the chat. Use when credentials are missing or rejected. |
| `{ "connection_required": true, "provider": "<id>", "message": "…" }` (plus your own `error` code) | Loop stops; the connected AI client relays `message` as a "connect it first" prompt instead of guessing. Use when credentials are missing or rejected. |
| `{ "error": "<provider>_access_denied", "provider": "<id>", "message": "…", "diagnostic_log": "…" }` | Loop stops with the message (and the log path, if given). Use for permission failures while connected. |
| `{ "error": "…", "message": "…" }` without those markers | **Not** terminal — the model sees the error and may correct itself (fix a query, choose another tool). Use for ordinary failures. |

Expand Down
6 changes: 3 additions & 3 deletions docs/extensions/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pages cover [API-key](./api-key-extensions.md) and
An extension is a small program that speaks the **Model Context Protocol (MCP)**. It
advertises a set of **tools** (each with a name, description, and JSON-Schema input)
and executes them when the model calls. NeatContext launches your extension, asks it
what tools it has, and routes tool calls to it during chat.
what tools it has, and routes a connected AI client's tool calls to it.

A NeatContext extension is a folder containing:

Expand Down Expand Up @@ -135,8 +135,8 @@ return a *connection-required* result instead of failing:
"provider": "myservice", "message": "Connect MyService before searching logs." }
```

NeatContext stops the tool loop, shows your `message` as the answer, and renders a
**Connect &lt;Extension&gt;** button in the chat. Rejected credentials
The connected AI client relays your `message` — a "connect it first" prompt — instead
of guessing; connect the extension in NeatContext and the next call works. Rejected credentials
(`"error": "myservice_access_denied"`, optionally with `connection_required: true`)
behave the same. Ordinary failures (bad query, timeout) should **not** set these
fields — the model can then correct itself and retry. The exact contract is in the
Expand Down
2 changes: 1 addition & 1 deletion docs/features/_category_.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"position": 4,
"link": {
"type": "generated-index",
"description": "A detailed guide to every part of NeatContext — chats and tabs, domain profiles, knowledge bases, model providers, extensions, and your account."
"description": "A detailed guide to every part of NeatContext — Contexts, the Library, domain profiles, knowledge bases, connecting AI clients, extensions, activity logs, and your account."
}
}
14 changes: 8 additions & 6 deletions docs/features/account.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
---
sidebar_position: 6
sidebar_position: 8
---

# Account

The desktop app asks you to **sign in** the first time you open it. Your account
identifies your subscription; your actual working data (profiles, knowledge,
chats, keys) stays local either way.
identifies your subscription; your actual working data (profiles, knowledge
folders, Contexts) stays local either way. NeatContext stores **no model
credential** — there is no model API key to keep.

## Sign in

On first launch you can **create an account** (email + password, confirmed with a
verification code sent to your inbox) or **sign in** to an existing one. Forgot
your password? The reset flow emails you a code.

Once signed in, the top bar shows your plan as a badge next to the account
button. Click it any time to open the **Account** page:
Once signed in, your plan is shown as a badge next to the account entry. Open the
**Account** page any time:

![The Account page](/img/features/account.png)

## Plans

Some workspace limits depend on your plan. For current plans and pricing, see
Some limits depend on your plan — the number of Contexts, knowledge folders per
Context, and enabled extensions. For current plans and pricing, see
**[neatcontext.com/pricing](https://www.neatcontext.com/pricing)** — upgrading
and managing your subscription is done right from the Account page.

Expand Down
Loading
Loading