Metadata-Version: 2.5
Name: cobalt-grinding
Version: 0.1.3
Summary: Cobalt Grinding — an agentic LLM-Wiki: ingest sources, retrieve, converse.
Author-email: Gary Frattarola <garyf@parkviewlab.ai>
License-Expression: AGPL-3.0-or-later
License-File: LICENSE
Requires-Python: >=3.13
Requires-Dist: anthropic<1.0,>=0.97
Requires-Dist: click>=8.1
Requires-Dist: fastembed
Requires-Dist: lancedb>=0.30
Requires-Dist: mcp[cli]<2,>=1.27
Requires-Dist: numpy
Requires-Dist: platformdirs>=4.0
Requires-Dist: pyarrow
Requires-Dist: pydantic>=2.6
Requires-Dist: tomlkit
Description-Content-Type: text/markdown

# Cobalt Grinding (`cobalt-grinding`)

An agentic LLM-Wiki served as an MCP server. Point it at a directory, file, or URL; it ingests the contents into a markdown-canonical corpus of interlinked notes with structured metadata; serves the result through hybrid retrieval and a conversational interface; and runs the scientific method on itself to grow + audit + propose.

CoGrind is **an MCP server wrapped around an AI brain** — see [`docs/northstar.md`](docs/northstar.md). How the code is put together is described in [`docs/architecture.md`](docs/architecture.md), the dated decisions behind it are in [`docs/decisions.md`](docs/decisions.md), and what is proposed but not built is in [`docs/in-flight_ideas.md`](docs/in-flight_ideas.md); the reasoning of the design conversation that shaped it is in [`docs/architecture-why.md`](docs/architecture-why.md).

## Status

The daemon (`cobalt-grinding`) serves twelve `wiki.*` tools for three cognitive skills (Ingest, Retrieve, Converse) and supervises four sibling MCP children:

- [`smalt-mcp`](https://github.com/ParkviewLab/smalt-mcp) — the Smalt (canonical knowledge): markdown wiki + LanceDB hybrid retrieval.
- [`ebony-enriching`](https://github.com/ParkviewLab/ebony-enriching) — the lab notebook: proposals, experiments, gaps.
- [`deco-assaying`](https://github.com/ParkviewLab/deco-assaying) — code parsing (tree-sitter).
- [`flint-slating`](https://github.com/ParkviewLab/flint-slating) — PDF reading: the text and metadata of local and remote PDFs.

The default configuration starts all four, and flint-slating is the daemon's only reader of PDFs, but the install line and the Docker image below install only the first three, so flint-slating's start fails and PDF ingestion has no reader. The daemon starts each child over stdio, whereas the children start as HTTP servers by default and ebony-enriching has no stdio mode, so with the default configuration no child completes its start.

The three cognitive skills are served through the `wiki.*` MCP surface:

- `wiki.ingest` — file, directory, git URL (shallow clone), or PDF URL → SourcePages + EntityPages + glossary ConceptPages + cross-page links + code symbol outlines (via deco-assaying).
- `wiki.search` / `wiki.get_page` / `wiki.traverse` — hybrid retrieval + 1-hop graph expansion.
- `wiki.ask` — cited natural-language answer with hallucination flagging.
- `wiki.find_gaps` / `wiki.report_gap` — knowledge-gap queue.

## Running

`cobalt-grinding` is the daemon binary; the user-facing CLI lives in the sibling [`cogrind-workshop`](https://github.com/ParkviewLab/cogrind-workshop) repo, and Claude Desktop / Claude Code can connect over MCP directly.

### From source

```sh
uv sync
# Install the children you want supervised (each is a standalone MCP server):
uv pip install smalt-mcp ebony-enriching deco-assaying
# Run the daemon — streamable-HTTP transport on 127.0.0.1:7474 by default:
uv run cobalt-grinding
```

### From the published Docker image

The image bundles cobalt-grinding and three of the sibling MCP servers (smalt-mcp, ebony-enriching and deco-assaying, not flint-slating), and takes your Anthropic API key and a host directory to mount as `/data`. The servers cannot run in the image at present: the image installs mcp 2.2.0 for them, outside the lockfile, and each crashes on import; and, as above, the daemon starts them over stdio while they start as HTTP servers by default.

```sh
docker run \
  -p 7474:7474 \
  -v ./data:/data \
  -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
  ghcr.io/parkviewlab/cobalt-grinding:latest
```

Or pull a specific version: `ghcr.io/parkviewlab/cobalt-grinding:0.1.0`.

### Configuration

Bootstrap runs on every startup and is idempotent: the daemon waits for the smalt-mcp and ebony-enriching children to handshake, then calls each one's `bootstrap` tool. Defaults: `SMALT_DIR=~/Documents/Smalt`, `EBONY_ENRICHING_DIR=~/Documents/EbonyEnriching`. Overrides via `--smalt`, env vars (`COBALT_GRINDING_SMALT_DIR`, `COBALT_GRINDING_EBONY_DIR`), or a `config.toml`. See `uv run cobalt-grinding --help`.

To use as a stdio-transport MCP server (e.g. from Claude Desktop): `cobalt-grinding --transport stdio`.

## Releasing

Tag-driven via [`.github/workflows/release.yml`](.github/workflows/release.yml). A push of a `v*` tag fires four jobs: a **gate** (tag matches the `pyproject.toml` version, which carries no dev marker; tag reachable from `origin/main`; version strictly greater than the previous release tag) that gates the two **publish** jobs (PyPI + GHCR Docker), and a **changelog** job that runs after the publishes — it generates the new `CHANGELOG.md` section (LLM-written "Highlights" header + categorized list written by dev-tools' `generate-changelog`), commits it back to `main`, and creates the GitHub Release with the same content as its body.

The procedure, including the `develop` → `main` promotion, is the ParkviewLab handbook's [Cutting a release](https://github.com/ParkviewLab/handbook/blob/main/docs/releases.md#cutting-a-release), run with the [`ParkviewLab/dev-tools`](https://github.com/ParkviewLab/dev-tools) helpers (`git bump`, `git release`, and `git back-merge`, which ends every release by a pull request into `develop`; see the handbook's [The release's last step](https://github.com/ParkviewLab/handbook/blob/main/docs/releases.md#the-releases-last-step-the-back-merge-pull-request)); install them with `git clone https://github.com/ParkviewLab/dev-tools.git ~/dev-tools && cd ~/dev-tools && ./install.sh`.

### Commit message convention

The changelog job groups the release's pull requests by the [Conventional Commits](https://www.conventionalcommits.org/) type of each title (the full list is in the ParkviewLab handbook's `commits-and-changelogs.md`), and lists under Direct commits any commit that reached the release without a pull request; a bookkeeping commit (a version bump, a change to `CHANGELOG.md` alone, a trivial merge) is left out of both:

| Title | Group in the notes | Notes |
|---|---|---|
| any type with `!` after it (`feat!:`), or a breaking-change footer | Breaking changes | listed there once, whatever its type |
| `feat:` | Features | user-visible |
| `fix:` | Bug fixes | user-visible |
| `perf:` | Performance | user-visible |
| `refactor:` | Refactor | |
| `docs:` | Docs | |
| `test:` | Tests | |
| `revert:` | Reverts | GitHub's Revert button titles a PR `Revert "…"`, which has no type |
| `build:` / `chore:` / `ci:` / `style:` | Maintenance | |
| any other title | Other changes | the whole title |
| a commit with no pull request | Direct commits | its subject and short hash |

A title without a recognised type is not dropped: it is listed whole under Other changes. So prefix your PR titles, and correct a title before the merge, since retitling afterwards does not change the commit. The groups appear in the order above, and an empty group is left out.

## License

Cobalt Grinding is **dual-licensed**. By default it is free software under the **GNU Affero General Public License v3.0 or later** (`AGPL-3.0-or-later`); see [`LICENSE`](LICENSE) for the full text. A separate **commercial license** is available from the copyright holder for use that cannot comply with the AGPL (e.g. embedding in a closed-source product). See [`LICENSING.md`](LICENSING.md) for details.

Copyright © 2026 Gary Frattarola.
