Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mitchella — Estate front desk · signals first, then the docs

main License Ask DeepWiki

Claude Python Slack Grafana

mitchella

Mitchella (partridgeberry — the botanical codename line alongside lentago, solidago, kalmia, drosera, claytonia, and betula) is a corpus-backed front desk for an infrastructure estate: a chat assistant that answers operator questions from documentation in git, checks live state before it answers, and routes what it cannot answer to a human. Partridgeberry's paired flowers fuse into a single berry — several sources, one answer.

Slack is the first surface. It is not the product: the core is UI-agnostic and the CLI ships alongside it, because a boundary with one implementation behind it is a boundary nobody has tested.

Authorship: The code and documentation in this repo are co-written with Claude (Anthropic). I direct the work and review the output; Claude writes the code. I'm an infrastructure operator, not a software engineer — please don't read this repo as a portfolio of coding ability.

🌱 This repo is one exhibit in Lentago Labs — a team learning lab where IT-operations people build, break, and operate real systems at deliberately non-critical stakes. mitchella's job in that estate is the front desk: it answers from documentation, defers to drosera on what is happening right now, and hands everything else to a person.

The three ideas worth stealing

1. Live state is checked before the corpus is allowed to answer. The failure that kills documentation-backed bots is not a wrong answer — it's a right answer to the wrong question. Mid-outage, someone asks "why can't I log in?" and a bot with excellent documentation walks them through a password reset, because that genuinely is the fix when the system is healthy. Forty people get the same advice and the real incident goes unmentioned.

So an open incident matching the question overrides the corpus, and the override is a branch in Python, not a line in the prompt — guidance is what a model gets talked out of. See ADR-0001.

2. There is no vector database, on purpose. The whole corpus goes in the prompt behind one cache breakpoint. At this size that is cheaper, simpler, and deletes a category of bug — "why did it retrieve the wrong document?" is only possible if you are retrieving. It costs one discipline: the cached prefix must be byte-stable, so nothing per-request ever renders into the system prompt, and a test enforces that. See ADR-0002.

3. It improves by measuring demand, not by learning in place. The desk logs every turn and reports which questions it couldn't answer, how many distinct people asked, and what kind of work would close each gap. It writes no documentation: for a curated corpus, an agent drafting pages about an estate it has only read about produces confident text with nothing behind it. Distinct-asker counts turn "is this worth documenting?" into a measurement, and a person closes the gap. See ADR-0004.

See ROADMAP.md for what MVP means here, what is missing, and the order it is being built in.

What it is not

  • It cannot change anything. No tools, no write access, no submit button — its output for an actionable request is a ticket draft a human sends. The corpus and the questions are both prompt-injection vectors, and containment is the mitigation (ADR-0005).
  • It does not own the live pane. drosera does. mitchella reads drosera's published status.json; it never queries the log archive, which is betula's. Neither product grows into the other's role.
  • It does not measure its own quality by cache hit rate. That is a cost metric. A bot answering the same question wrong four hundred times has an excellent cache hit rate.

How it answers

question ──▶ signal plane ──┐
                            ├──▶ decide ──▶ answered / incident / escalated / declined
             corpus ────────┘
Outcome Meaning
answered Answered from the corpus, with entry ids cited.
incident A live incident explains the question. Corpus answer suppressed.
escalated Not documented. A ticket draft is attached for a human to submit.
declined Out of scope, or the model declined. No guess, no draft.

Every outcome carries degraded_signals — the signal sources that could not be read. Borrowed from drosera's status page rule: degrade gracefully, never fake green. An unreachable feed means unknown, never all clear, and every frontend is required to show it.

Run it

pip install -e '.[dev,slack]'
export ANTHROPIC_API_KEY=...          # or `ant auth login`

python -m frontends.cli.main --corpus-info      # no API call
python -m frontends.cli.main --usage "how do I share a file on the LAN?"
python -m frontends.cli.main                    # interactive

Declare an incident by uncommenting the block in signals/incidents.toml, then ask a question that mentions one of its subjects and watch the answer change. That one file is the cheapest useful thing here: a person on the desk knows about an outage before the monitoring does more often than anyone likes to admit.

Wire in drosera's live feed with MITCHELLA_DROSERA_STATUS (a URL, or a local path to a status.json from a drosera build).

Pointing at a documentation tree elsewhere

The corpus does not have to live in this repo. The wiki source reads a tree of long-form markdown pages in place, deriving ids from paths, titles from the first # H1, tags from frontmatter plus the containing directory, and a certainty tier from an evidence-basis notice if the tree uses one. Nothing is copied here, which matters when the documentation and the bot have different homes or different confidentiality rules.

MITCHELLA_CORPUS_DIR=~/path/to/wiki MITCHELLA_CORPUS_SOURCE=wiki \
  python -m frontends.cli.main --corpus-info

Where a tree marks its pages as inferred rather than verified, the desk is required to preserve that: it reports what the documentation records rather than asserting it as fact, and it never turns an absence in the documentation into a claim that something does not exist.

Slack

export SLACK_BOT_TOKEN=xoxb-...   # Bot User OAuth Token
export SLACK_APP_TOKEN=xapp-...   # App-Level Token, scope connections:write
python -m frontends.slack.app

Socket Mode, so no public URL and no inbound firewall change. Scopes: app_mentions:read, chat:write, im:history, im:read, im:write. Event subscriptions: app_mention, message.im.

The demand loop

python -m jobs.promote --since 7               # print the report
python -m jobs.promote --since 7 --out demand.md

Reports unanswered questions clustered by underlying need, ranked by distinct askers, each routed to the kind of work that would close it (intake, research, verification, decision, ticket). It writes no documentation.

Layout

Path What
mitchella/contract.py The frontend boundary — Query in, Answer out
mitchella/engine.py Prompt assembly, the incident gate, the API call
mitchella/signals.py Live state; degrades to unknown, never to healthy
mitchella/corpus.py Markdown → one deterministic, cacheable block
mitchella/sources.py Document shapes: flat (this repo) and wiki (a tree elsewhere)
corpus/ The desk's own entries. Changes on merge and nowhere else
signals/incidents.toml The manual override channel
frontends/slack/render.py Block rendering, testable without a workspace
frontends/slack/, frontends/cli/ The clients
jobs/promote.py The demand loop
docs/adr/ Why it is shaped this way

Configuration

All optional; every value has a working default.

Variable Default Notes
MITCHELLA_MODEL claude-opus-5 One model for every stage — caches are model-scoped, so a cheap-classifier cascade forfeits prefix reuse
MITCHELLA_EFFORT high Triage is intelligence-sensitive. medium is the documented step-down to measure, not to assume
MITCHELLA_CACHE_TTL 1h A desk goes quiet between questions; a 5-minute entry would expire in the gaps
MITCHELLA_CORPUS_DIR corpus Where the documents are. May point outside this repo
MITCHELLA_CORPUS_SOURCE flat flat (this repo's format) or wiki (a documentation tree)
MITCHELLA_DROSERA_STATUS (unset) URL or path to drosera's status.json
MITCHELLA_INCIDENTS signals/incidents.toml The manual override file
MITCHELLA_TURNLOG var/turns.jsonl Feeds jobs/promote.py

Tests

python -m pytest

They run against a fake client and cost nothing. They do not test what Claude says — they test the guarantees that hold whatever it says: the cached prefix is byte-stable, an open incident overrides an answered verdict, citations to non-existent entries are dropped, a refusal is caught before content is read, and an unreachable signal source degrades to unknown rather than healthy.

About

Mitchella — the Lentago Labs estate front desk: a corpus-backed chat assistant that checks live state before answering from documentation, and drafts a ticket for a human when it cannot. Partridgeberry: paired flowers, one berry — several sources, one answer.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages