Project knowledge¶
The corpus is machine-global. A context bundle is the other scope: a
.context/ directory at the root of one project, holding what is true about
that project and committed with it, so the knowledge travels with a clone.
The index does not travel. It is derived from the documents beside it,
rebuilt in milliseconds, and specific to whoever built it, so context init
gitignores it and a clone runs kennis context index once.
Create one¶
A bundle is written and indexed by the kennis service, which belongs to a
corpus, so this needs one on the machine: run kennis corpus init first if
there is none. It is offline and takes a moment. The bundle itself stays in
your project and is never copied into the corpus.
It walks up from where you are to the nearest .git and creates the bundle
at the workspace root, so running the command three directories deep does
not bury it there. The path is reported for that reason. --here overrides
the walk and creates it in the working directory.
It scaffolds three things:
| file | what it is |
|---|---|
bundle.json |
the manifest that marks this directory as a bundle |
LANDING.md |
the entry point, written for an agent: read this first, then jump |
.skeleton.md |
the template a file at this level is copied from |
.gitignore |
one line, .index/, keeping the index out of the repository |
Re-running it is safe, and converging rather than merely harmless: a scaffold file you deleted is written again, and anything you added is left alone.
In the window¶
The window manages projects from the pane's Context section. The button at
the right of the Context heading adds a project: choose its folder, and
kennis lists it if it already has a .context/ folder, or creates one there
and lists it. The window uses the folder you chose; unlike kennis context
init, it does not walk up to the repository's root.
Each project's menu, the button at the right of its row, has:
| entry | what it does | the command |
|---|---|---|
| Packs this project uses | a checkbox per installed pack; saving declares exactly what is checked, then opens the sync dialog. A pack the project declares that this machine has not installed is shown checked, so saving keeps it | kennis context packs |
| Sync this project's context | says which pack files it will copy in or update and which it leaves, then copies them; the copies of a pack the project no longer uses go only if you tick "Remove them" | kennis context sync |
| Index this project's context | builds its index, as a task in the strip | kennis context index |
| Reset this project's context | lists what goes, then removes it | kennis context reset |
| Forget this project | takes it off the list; its files stay | kennis context forget |
| Delete this project's context | deletes .context/, after asking |
kennis context delete |
A project whose folder has gone is listed as missing, with Forget alone.
Write something down¶
kennis remember --context "Calibration runs in four-minute chunks."
kennis remember --context --title "Solver choice" "We use quartical."
kennis remember --context --group decisions "Solved per scan, not per field."
--title names the file; without one the title is derived from the first
line. --group files it in a subdirectory, which is created if it is not
there yet. The same text twice writes one file - deduplication is on the
body, so the same prose under another name in another directory is still
recognised.
Every file carries owner: user in its frontmatter, which is what stops any
future pack from overwriting it.
kennis does not commit for you. The bundle lives in a repository kennis
does not own, so committing .context/ is yours to do, whenever you want
it shared with the project.
Index it¶
BM25 only, and offline. A dense index would turn setting a project up into a model download, and a bundle is small enough that lexical search over it is the right answer rather than a concession - a three-document bundle indexes in about 4ms and produces under 3 KB.
retrieval.context_method changes it, and defaults to bm25 for that
reason. Setting it to hybrid or dense gives the bundle a model-specific
index and needs an embedding backend; with none configured, asking for
hybrid still produces a lexical index rather than an error. The setting is
yours alone - the index is not shared, so nobody else in the project is
affected by it.
The index is written inside the bundle, at .context/.index/, and
context init gitignores that directory. Inside so that it travels with the
bundle if you move the project; ignored because it is derived and because
what it was built with - your chunk settings, and your embedding model if
you configured one - is yours rather than the project's.
A fresh clone has the documents and no index. kennis search says so
and names this command; run it once and the clone searches with your own
settings.
What is and is not indexed¶
Three rules, and they are the whole of it:
- A file with no frontmatter is not indexed. The header - the block
between two
---lines at the top - is what makes a file a note kennis can describe, so a README or an export kept beside your notes stays out of search. Everything kennis writes has one. A header that is empty or cannot be read counts as none. To index such files too, set"index_without_frontmatter": trueinbundle.json;kennis context initwrites the key, set tofalse, so you can find it. - A dot-prefixed path is never indexed or searched, at any depth. That
is why the templates are
.skeleton.md: a template matches every query about its own section and answers none of them. Rename any file of your own to.name.mdto keep it out of search without deleting it. LANDING.mdis not indexed either. It is a map rather than an answer, and it has to stay discoverable to an agent told to read it first, so it cannot be hidden by the dot trick.
Check on it¶
What the bundle holds, broken down by group when there is more than one, and whether the index is in step with it.
Freshness is answered differently here than for the corpus. A corpus index
records the commit it was built from and the question is a git diff;
kennis does not write to your repository, so a bundle index records no
commit and the comparison is made against the document digests the index
stored. Same three counts either way:
| line | what it means |
|---|---|
in step |
the index matches the bundle |
in step, with N not yet indexed |
you have written since the last build - the index holds less, not something wrong |
stale: N changed, N gone |
the index holds something false |
remember --context does not index, so the middle line is the ordinary
state of a bundle rather than a brief window.
A file whose frontmatter block could not be read is listed with a !, and
the files with no frontmatter are listed after a note saying they are not
indexed. Neither is indexed unless bundle.json says
"index_without_frontmatter": true; then a broken header costs only its
metadata, since a bundle document's identity is its path.
Start again¶
Removes the index and anything kennis owns, and keeps your own files. It
asks first and names what will go; -y skips the question.
Files kennis owns are the files a pack applied - the ones carrying
owner: pack:<id>. Everything remember --context writes is owner: user,
and so is anything you wrote by hand, including a file with no frontmatter at
all and one whose header kennis cannot read. The two mistakes do not cost the
same: keeping a pack's file costs a stale file the next sync overwrites, and
deleting yours costs your writing.
LANDING.md, .skeleton.md, bundle.json and .gitignore are left alone
even though kennis wrote them, because you are expected to edit the first
two. kennis context init puts back any one of them you delete.
There is no undo inside kennis. A bundle lives in your repository and kennis
keeps no history of it, so git checkout is the way back - if you
committed.
Stop listing a project¶
Takes the project off kennis's list of projects, which is what the window's
pane and kennis context list show. Nothing in its folder is changed: the
bundle keeps every file. kennis lists the project again the next time a
kennis command runs in that folder. In the window, the same is "Forget this
project" in the project's row menu in the pane, which asks first.
Delete a project's context¶
Deletes the project's .context/ folder - every file in it and its index -
and takes the project off the list. kennis cannot undo this. The bundle
lives in your repository and kennis keeps no history of it, so what you
committed comes back with git checkout, and nothing else comes back. The
rest of the project is not touched.
It asks first, naming the folder and how many files it holds; -y skips the
question. It refuses a project whose bundle is no longer there, and a listed
folder that is not a .context folder holding bundle.json, and names
kennis context forget for both. In the window, the same is "Delete this
project's context" in the project's row menu, which asks in a dialog first.
Use a pack¶
kennis context packs <id> # declare it; --drop <id> to stop
kennis context sync # copy its context in
A pack is knowledge that arrives from outside, as data - see
Author a pack. kennis pack install puts it in this
machine's store. A project declares the packs it uses in bundle.json,
which is committed, so whoever clones the project declares the same ones.
kennis context sync then copies the context of each declared pack into
.context/, at the paths the pack gives, and the project indexes and
searches those copies as its own files.
Nothing reaches a project except through its own sync. Declaring a pack
copies nothing, and a new release of a pack changes no project until you
run sync there. What it changed is then a diff in your repository, to read
before you commit. Offline: the content is already on this machine.
Each file it writes carries owner: pack:<id>, which is what tells kennis's
files from yours:
| the file | what sync does |
|---|---|
anything with owner: user, or no frontmatter |
never touched |
a file with owner: user at a path a pack ships |
left alone, and said |
| a pack's copy you have edited in place | left alone and named; your edit stays |
| a pack's copy you have not touched | replaced when the pack ships a change |
| a copy of a pack the project no longer declares | kept, and said, until you sync with --remove-undeclared; an edited one is kept even then |
| a copy of a pack the project declares and this machine has not installed | kept: whoever has the pack relies on it |
To make a pack's file yours, say so in its header. Change owner: to
user: from then on no release reaches it. A copy you edited without doing
so is left as it is and named on every sync, with that instruction; delete
it to take the pack's text again.
A damaged pack stops the sync rather than emptying your bundle. If a
pack's store is missing content, or its stored declaration will not parse,
kennis refuses and names the pack. kennis pack status says what is wrong
and how to repair it.
Two things a pack may not do, both refused with the file named:
- ship a dot-prefixed file. A dot-prefixed path is never indexed, so the file would be copied and then invisible to search.
- write
LANDING.md. It is the entry point, and it is yours.
When two declared packs ship the same path, the one installed first keeps it, and the sync says so.
sync does not index. It names kennis context index when it changed
something, for the same reason remember --context does.
kennis does not commit, here either.
Search it¶
kennis search "four-minute chunks" # every scope
kennis search "four-minute chunks" --collection context
A context hit's handle is path=.context/..., because a bundle file is a
file in your own project. There is no kennis read for one - open it with
your own tools.
See Search and read for how the scopes interact.