@falkenslab/agent-kit 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/assets/knowledge-plugin/.claude-plugin/plugin.json +4 -0
  4. package/assets/knowledge-plugin/commands/ingest.md +7 -0
  5. package/assets/knowledge-plugin/commands/lint.md +5 -0
  6. package/assets/knowledge-plugin/commands/query.md +5 -0
  7. package/assets/knowledge-plugin/skills/knowledge-ingest/SKILL.md +42 -0
  8. package/assets/knowledge-plugin/skills/knowledge-lint/SKILL.md +26 -0
  9. package/assets/knowledge-plugin/skills/knowledge-pages/SKILL.md +137 -0
  10. package/assets/knowledge-plugin/skills/knowledge-query/SKILL.md +14 -0
  11. package/dist/core/agentSpec.d.ts +132 -0
  12. package/dist/core/agentSpec.js +1 -0
  13. package/dist/core/claudeAuth.d.ts +24 -0
  14. package/dist/core/claudeAuth.js +27 -0
  15. package/dist/core/hooks/fileScopeGate.d.ts +33 -0
  16. package/dist/core/hooks/fileScopeGate.js +68 -0
  17. package/dist/core/hooks/humanInput.d.ts +15 -0
  18. package/dist/core/hooks/humanInput.js +52 -0
  19. package/dist/core/hooks/stepGate.d.ts +11 -0
  20. package/dist/core/hooks/stepGate.js +47 -0
  21. package/dist/core/hooks/subagentBashGate.d.ts +28 -0
  22. package/dist/core/hooks/subagentBashGate.js +40 -0
  23. package/dist/core/hooks/subagentForegroundGate.d.ts +18 -0
  24. package/dist/core/hooks/subagentForegroundGate.js +34 -0
  25. package/dist/core/hooks/subagentTypeGate.d.ts +16 -0
  26. package/dist/core/hooks/subagentTypeGate.js +33 -0
  27. package/dist/core/hooks/transcriptLogger.d.ts +14 -0
  28. package/dist/core/hooks/transcriptLogger.js +66 -0
  29. package/dist/core/interaction.d.ts +29 -0
  30. package/dist/core/interaction.js +7 -0
  31. package/dist/core/knowledge.d.ts +15 -0
  32. package/dist/core/knowledge.js +54 -0
  33. package/dist/core/mcpPermissions.d.ts +23 -0
  34. package/dist/core/mcpPermissions.js +47 -0
  35. package/dist/core/promptTemplate.d.ts +6 -0
  36. package/dist/core/promptTemplate.js +20 -0
  37. package/dist/core/runner.d.ts +137 -0
  38. package/dist/core/runner.js +115 -0
  39. package/dist/core/session.d.ts +63 -0
  40. package/dist/core/session.js +222 -0
  41. package/dist/core/toolLabels.d.ts +23 -0
  42. package/dist/core/toolLabels.js +114 -0
  43. package/dist/core/tools/humanApproval.d.ts +14 -0
  44. package/dist/core/tools/humanApproval.js +37 -0
  45. package/dist/core/tools/manualLogin.d.ts +16 -0
  46. package/dist/core/tools/manualLogin.js +27 -0
  47. package/dist/core/tools/saveToSources.d.ts +10 -0
  48. package/dist/core/tools/saveToSources.js +105 -0
  49. package/dist/index.d.ts +31 -0
  50. package/dist/index.js +32 -0
  51. package/dist/tui/chatTui.d.ts +105 -0
  52. package/dist/tui/chatTui.js +265 -0
  53. package/dist/tui/claudeAuth.d.ts +19 -0
  54. package/dist/tui/claudeAuth.js +96 -0
  55. package/dist/tui/consoleRenderer.d.ts +32 -0
  56. package/dist/tui/consoleRenderer.js +72 -0
  57. package/dist/tui/ink/PromptInput.d.ts +40 -0
  58. package/dist/tui/ink/PromptInput.js +333 -0
  59. package/dist/tui/ink/SessionView.d.ts +42 -0
  60. package/dist/tui/ink/SessionView.js +223 -0
  61. package/dist/tui/ink/fileMentions.d.ts +13 -0
  62. package/dist/tui/ink/fileMentions.js +50 -0
  63. package/dist/tui/ink/fullscreen.d.ts +79 -0
  64. package/dist/tui/ink/fullscreen.js +175 -0
  65. package/dist/tui/ink/header.d.ts +17 -0
  66. package/dist/tui/ink/header.js +24 -0
  67. package/dist/tui/ink/inkInteraction.d.ts +22 -0
  68. package/dist/tui/ink/inkInteraction.js +64 -0
  69. package/dist/tui/ink/lineBuffer.d.ts +28 -0
  70. package/dist/tui/ink/lineBuffer.js +87 -0
  71. package/dist/tui/ink/markdown.d.ts +12 -0
  72. package/dist/tui/ink/markdown.js +148 -0
  73. package/dist/tui/ink/progressView.d.ts +27 -0
  74. package/dist/tui/ink/progressView.js +65 -0
  75. package/dist/tui/ink/promptEditing.d.ts +54 -0
  76. package/dist/tui/ink/promptEditing.js +123 -0
  77. package/dist/tui/ink/runChatInk.d.ts +103 -0
  78. package/dist/tui/ink/runChatInk.js +298 -0
  79. package/dist/tui/ink/sessionModel.d.ts +85 -0
  80. package/dist/tui/ink/sessionModel.js +262 -0
  81. package/dist/tui/ink/terminalCursor.d.ts +32 -0
  82. package/dist/tui/ink/terminalCursor.js +68 -0
  83. package/dist/tui/ink/terminalStatus.d.ts +20 -0
  84. package/dist/tui/ink/terminalStatus.js +55 -0
  85. package/dist/tui/ink/toolGroup.d.ts +36 -0
  86. package/dist/tui/ink/toolGroup.js +77 -0
  87. package/dist/tui/ink/wizard.d.ts +62 -0
  88. package/dist/tui/ink/wizard.js +167 -0
  89. package/dist/tui/promptErrors.d.ts +2 -0
  90. package/dist/tui/promptErrors.js +4 -0
  91. package/dist/tui/terminalInteraction.d.ts +18 -0
  92. package/dist/tui/terminalInteraction.js +85 -0
  93. package/dist/tui/ui.d.ts +21 -0
  94. package/dist/tui/ui.js +25 -0
  95. package/package.json +75 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Francisco Vargas Ruiz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # agent-kit
2
+
3
+ A foundation for building AI agents on top of the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk). It isn't an agent itself: it solves once what every agent needs (human oversight, safety, memory and a good terminal interface), so each concrete agent only has to write what belongs to its own domain: what it knows how to do, with which tools, and how it talks.
4
+
5
+ > **Status:** version `0.x`, still evolving. MIT license.
6
+
7
+ ## What an agent built with it can do
8
+
9
+ - **Work at different levels of oversight.** Autonomous, guided (it asks for permission before anything that can't be undone or that other people will see) or step by step (it asks before every action). Within the same conversation you can switch from guided to step by step and back.
10
+ - **Ask a person for help.** It asks for approvals, or stops so someone can do something by hand, such as signing in to a website. It can be answered from the keyboard or from another program driving it, for example a desktop app.
11
+ - **Remember between sessions.** It keeps its own knowledge base, a small wiki of notes that grows with every session, and keeps the original documents you give it or that it downloads untouched.
12
+ - **Delegate to subagents safely.** Only to the ones it declares, always waiting for their result, and without the main agent being able to slip past its own limits through them.
13
+ - **Stay within limits.** It only reads and writes in the folders that belong to it, and never in protected files, such as one holding passwords.
14
+ - **Use external tools.** MCP servers of its own or of the project, and skills and commands organized in plugins.
15
+ - **Leave a trail.** It records every action and the whole conversation, with secrets hidden.
16
+ - **Chat in a terminal the way Claude Code does.** Full screen, with the reply written live and its markdown already formatted, the tools it uses summed up in one line (Ctrl+O unfolds it), panels for approvals, history and search, a suggestion for the next message, pasted blocks, file mentions with `@`, mouse selection (right-click to copy), and the agent's status in the tab and in the Windows taskbar.
17
+ - **Also work without a terminal.** The same foundation runs inside a desktop app or a server, which bring their own interface.
18
+
19
+ ## Examples
20
+
21
+ ### Captain Whiskers
22
+
23
+ [Captain Whiskers](./examples/captain-whiskers) is a toy agent to see the kit in action: a retired pirate cat who tells jokes in the terminal, in Spanish. It starts full screen with its logo and has a small crew of subagents: one looks for new jokes on the web, another rates them before they're told, and a third, optional one tells the time. It lets you try the different levels of oversight and is the best starting point for an agent of your own. Its README explains how to run it.
24
+
25
+ ![Captain Whiskers in Windows Terminal: its logo at the top, the conversation in the middle and the framed prompt at the bottom, with a suggestion for the next message](docs/assets/captain-whiskers.png)
26
+
27
+ ### teacher-agent
28
+
29
+ [teacher-agent](https://github.com/falkenslab/teacher-agent) is a real assistant for Moodle teachers. It signs in with your account in a Chrome window and works as you would: it grades submissions, answers in the forum, creates or reviews content and sums up how the class is going. It asks for your permission before publishing anything students will see, and takes notes about the course to remember everything in the next session.
30
+
31
+ Oversight, memory, safety and the chat come from the kit; teacher-agent brings what it knows about Moodle and driving the browser.
32
+
33
+ ## Installation
34
+
35
+ ```
36
+ npm install @falkenslab/agent-kit
37
+ ```
38
+
39
+ To try changes to the kit without publishing them, point to a local clone with `"file:../agent-kit"` in your `package.json` and build it with `npm run build` after each change.
40
+
41
+ Requires Node.js 20 or later.
42
+
43
+ ## A minimal agent
44
+
45
+ An agent only describes what belongs to it (who it is, which MCP servers, skills and subagents it has) and picks a level of oversight; the kit sets up the session and the chat:
46
+
47
+ ```ts
48
+ import { mkdir } from "node:fs/promises";
49
+ import path from "node:path";
50
+ import { buildSessionOptions, ensureClaudeAuth, runChatInk, type AgentSpec, type BaseSessionConfig } from "@falkenslab/agent-kit";
51
+
52
+ // The only part specific to the agent: who it is and what it has.
53
+ const spec: AgentSpec<BaseSessionConfig> = {
54
+ buildSystemPrompt: () => "You are a pirate cat who tells jokes. Always answer in character.",
55
+ buildMcpServers: () => ({}), // its own MCP servers, if any
56
+ pluginRoots: () => [], // folders with skills and commands
57
+ buildSubagents: () => undefined, // subagents, if it delegates to any
58
+ };
59
+
60
+ await ensureClaudeAuth(); // offers to create a Claude token if it finds none
61
+
62
+ // Each session keeps its logs in a folder of its own.
63
+ const runDir = path.resolve(".run", new Date().toISOString().replace(/[:.]/g, "-"));
64
+ await mkdir(runDir, { recursive: true });
65
+
66
+ const config: BaseSessionConfig = { mode: "guided", projectDir: process.cwd() };
67
+ const { options, modeControl } = await buildSessionOptions(config, runDir, spec);
68
+
69
+ await runChatInk(options, {
70
+ header: { title: "My agent" },
71
+ mode: config.mode,
72
+ modeControl, // Shift+Tab switches between guided and step by step
73
+ fullscreen: true,
74
+ sessionLogPath: path.join(runDir, "session.log"),
75
+ });
76
+ ```
77
+
78
+ Save it as `agent.ts` in a project with the kit and `tsx` installed and `"type": "module"` in its `package.json`, and run it with `npx tsx agent.ts`. Captain Whiskers is this same skeleton with more pieces: skills, subagents and its logo.
79
+
80
+ ## More details
81
+
82
+ The specification in [`.minispec/`](./.minispec/README.md) explains how each part is built and why, including the SDK behaviors checked by hand that motivate several of its safeguards. Captain Whiskers' code is the quickest way to see how an agent is put together.
83
+
84
+ ## Development
85
+
86
+ | Command | What it does |
87
+ | --- | --- |
88
+ | `npm run build` | Builds the kit into `dist/` |
89
+ | `npm run typecheck` | Checks the types without building |
90
+ | `npm run lint` | Checks the code style |
91
+ | `npm test` | Runs all the tests |
92
+
93
+ To run a single test file:
94
+
95
+ ```
96
+ npx tsx --test test/tui/promptErrors.test.ts
97
+ ```
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "knowledge",
3
+ "description": "Built-in knowledge base workflows (an LLM wiki): page templates, ingesting sources, querying the knowledge base and health-checking it."
4
+ }
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: Ingest material into the knowledge base right now - the files or topic given, or everything in sources/ not ingested yet
3
+ ---
4
+
5
+ Apply the `knowledge-ingest` skill right now to: $ARGUMENTS
6
+
7
+ If nothing is given above, find every file in the sources folder that has no summary page in the knowledge base yet (check `index.md` and `summaries/`) and ingest them all. When you're done, summarize which pages you created and updated, and anything you couldn't read.
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Health-check the knowledge base right now - broken links, orphans, duplicates, contradictions, gaps
3
+ ---
4
+
5
+ Apply the `knowledge-lint` skill right now over the whole knowledge base. Fix what's mechanical (links, index, missing back-links) and report the rest: what needs the human's decision, and the gaps worth filling next.
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Answer a question from the knowledge base, and file the answer back if it is worth keeping
3
+ ---
4
+
5
+ Apply the `knowledge-query` skill right now to answer: $ARGUMENTS
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: knowledge-ingest
3
+ description: Ingest one source into the knowledge base - a file in sources/, a document, a page - creating its summary page, creating or updating the concept and entity pages it touches, linking everything both ways, and updating index.md and log.md.
4
+ ---
5
+
6
+ # Ingesting a source into the knowledge base
7
+
8
+ A source is ingested once, and from then on the knowledge base holds what it taught: later sessions read the pages, not the original again. Ingesting is not summarizing a file in isolation - its value is in how it connects to what the knowledge base already knows. Load the `knowledge-pages` skill first for the page templates.
9
+
10
+ ## 1. Check it isn't already ingested
11
+
12
+ Look for it in `index.md` (Summaries) or `Grep` its file name or URL inside the knowledge base. If it already has a page:
13
+ - unchanged source: nothing to do;
14
+ - the source changed or the page is thin: update that page instead of creating another.
15
+
16
+ ## 2. Read it for real
17
+
18
+ Read the whole source, not its first page. If it exists only outside the sources folder (a downloaded document, a remote file), save it with `save_to_sources` first, so the original is kept as obtained.
19
+
20
+ ## 3. Write the summary page
21
+
22
+ Create `summaries/<slug>.md` with the template: summary, key points (literal wording where exactness matters), frontmatter `file`/`url` pointing to the original.
23
+
24
+ ## 4. Update concepts and entities
25
+
26
+ For every concept or entity the source explains or relies on:
27
+ - no page yet: create it;
28
+ - page exists: add what is new (a better definition, an example, a nuance, a fact) with `Edit`, and link the summary under "Sources".
29
+
30
+ Check first whether it exists under another name (`Grep` the knowledge base for the term and look at `aliases`): a duplicate page is worse than none.
31
+
32
+ ## 5. Link both ways and look for conflicts
33
+
34
+ Every link you added from page A to page B needs its counterpart in B. If the source contradicts an existing page, record both versions with attribution in both pages - don't overwrite.
35
+
36
+ ## 6. Close
37
+
38
+ - `index.md`: new pages, and one-line descriptions that changed.
39
+ - `log.md`: `## [date] ingest | <source title>` with the pages created and updated.
40
+ - `overview.md`: only if the source changes the big picture.
41
+
42
+ When ingesting several sources in a row, do steps 1-5 for each and close once at the end.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: knowledge-lint
3
+ description: Health-check the knowledge base - broken links, pages missing from index.md, orphan pages, one-way links, duplicated concepts, mentioned-but-missing concepts, contradictions, gaps - fix what's mechanical and report the rest.
4
+ ---
5
+
6
+ # Linting the knowledge base
7
+
8
+ A knowledge base maintained across sessions drifts: links break, pages go unlisted, the same concept appears under two names. Lint it when asked and after a large ingest. Load `knowledge-pages` first for the templates.
9
+
10
+ ## Checks
11
+
12
+ Use `Glob` to list pages and `Grep` (always with `path` inside the knowledge base) to find links, instead of reading every page in full.
13
+
14
+ 1. **Broken links**: a relative link whose target file doesn't exist. Fix it if the right target is obvious (a typo, a page under a close name); otherwise report it.
15
+ 2. **Index**: every page is listed in `index.md` and every entry there points to an existing page. Fix it.
16
+ 3. **Orphans**: pages nothing links to (`Grep` for the file name). Link them from where they belong, or report why they don't belong anywhere.
17
+ 4. **One-way links**: a summary that feeds a concept which doesn't list it back... Add the missing side.
18
+ 5. **Duplicates**: two pages for the same idea under different names. Merge the content into one, mark the other as superseded (never delete it) and repoint links.
19
+ 6. **Missing pages**: terms that several pages treat as concepts or entities but have no page. Create them if the material is there; otherwise list them.
20
+ 7. **Contradictions**: claims that disagree across pages without being recorded as such. Record both sides, attributed.
21
+ 8. **Provenance**: claims with no traceable source. Add the link, or mark them as unsourced.
22
+ 9. **Gaps**: files in the sources folder with no summary page yet, concepts mentioned but never explained by any source. Report them - they are what to ingest or find next.
23
+
24
+ ## Close
25
+
26
+ Append `## [date] lint | <summary>` to `log.md` listing what was fixed. Then report to the human: what you fixed, and what needs their decision or more material. Don't make judgement calls silently - merging pages that are only similar, or choosing between contradictory sources, goes in the report.
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: knowledge-pages
3
+ description: Exact templates and conventions for every page of the knowledge base (index, log, overview, summary, concept, entity and synthesis pages) - load it before creating a knowledge base page or restructuring one, so every page keeps the same shape and links.
4
+ ---
5
+
6
+ # Knowledge base page templates
7
+
8
+ The knowledge base's layout and rules are in the system prompt ("Knowledge base"). This skill only adds the exact shape of each page. Headings and frontmatter keys stay in English (they are structure); the text under them is in the human's language. Dates are `YYYY-MM-DD`. Links are relative markdown links (from `concepts/x.md`, a summary is `../summaries/y.md`; an original file is `../../sources/...`, adjusted to where the folders really are).
9
+
10
+ Every page starts with YAML frontmatter; `updated` changes whenever you edit the page.
11
+
12
+ ## index.md
13
+
14
+ The catalog and entry point. One line per page, grouped by section: Summaries, Concepts, Entities, Syntheses (plus any section the domain adds).
15
+
16
+ ```markdown
17
+ # Index
18
+
19
+ ## Summaries
20
+ - [Q3 architecture review](summaries/q3-architecture-review.md) - decisions taken on the billing service
21
+ ## Concepts
22
+ - [Idempotency](concepts/idempotency.md) - safe retries of a request
23
+ ```
24
+
25
+ ## log.md
26
+
27
+ Append-only; never edit past entries. Newest at the bottom.
28
+
29
+ ```markdown
30
+ ## [2026-10-03] ingest | Q3 architecture review
31
+ - created: summaries/q3-architecture-review.md, concepts/idempotency.md
32
+ - updated: entities/billing-service.md, index.md
33
+ ```
34
+
35
+ ## overview.md
36
+
37
+ A living synthesis of the whole knowledge base, rewritten (not appended) as understanding grows: what it covers, its main blocks and how they connect (with links), what is still unknown.
38
+
39
+ ## Summary page (`summaries/<slug>.md`)
40
+
41
+ One per ingested source.
42
+
43
+ ```markdown
44
+ ---
45
+ type: summary
46
+ title: "<Title>"
47
+ file: <relative link to the original in sources/, if any>
48
+ url: <original URL, if any>
49
+ ingested: YYYY-MM-DD
50
+ updated: YYYY-MM-DD
51
+ ---
52
+
53
+ # <Title>
54
+
55
+ ## Summary
56
+ <Two to four paragraphs: what it actually says.>
57
+
58
+ ## Key points
59
+ - Claims, definitions or figures likely to be needed later, quoted literally when exact wording matters.
60
+
61
+ ## Pages it feeds
62
+ - [Concept or entity](../concepts/<slug>.md)
63
+
64
+ ## New or surprising
65
+ - What this source adds to what the knowledge base already had.
66
+
67
+ ## Contradictions
68
+ - Conflicts with other pages, linked.
69
+ ```
70
+
71
+ ## Concept page (`concepts/<slug>.md`)
72
+
73
+ One idea per page.
74
+
75
+ ```markdown
76
+ ---
77
+ type: concept
78
+ aliases: []
79
+ updated: YYYY-MM-DD
80
+ ---
81
+
82
+ # <Concept>
83
+
84
+ <Definition in one or two sentences.>
85
+
86
+ ## Explanation
87
+ <How it works, at the depth the sources give.>
88
+
89
+ ## Connections
90
+ - Requires: [Concept](<slug>.md)
91
+ - Related: [Concept](<slug>.md) - how
92
+
93
+ ## Sources
94
+ - [Summary](../summaries/<slug>.md) - what it says about this
95
+
96
+ ## Contradictions and open questions
97
+ - "<Source A> says X; <source B> says Y" - both attributed.
98
+ ```
99
+
100
+ ## Entity page (`entities/<slug>.md`)
101
+
102
+ A concrete thing: a system, a component, an organization, a document, a person only when they are a public role rather than private individual details.
103
+
104
+ ```markdown
105
+ ---
106
+ type: entity
107
+ kind: <system | component | organization | document | other>
108
+ aliases: []
109
+ updated: YYYY-MM-DD
110
+ ---
111
+
112
+ # <Name>
113
+
114
+ <What it is, one or two sentences.>
115
+
116
+ ## Facts
117
+ - Attributed facts, each linking the summary or source it comes from.
118
+
119
+ ## Connections
120
+ - [Concept or entity](../concepts/<slug>.md) - how
121
+ ```
122
+
123
+ ## Synthesis page (`syntheses/<slug>.md`)
124
+
125
+ An answer worth keeping: a comparison, an analysis, a report.
126
+
127
+ ```markdown
128
+ ---
129
+ type: synthesis
130
+ question: "<The question it answers>"
131
+ updated: YYYY-MM-DD
132
+ ---
133
+
134
+ # <Title>
135
+
136
+ <The answer, with links to every page it draws on.>
137
+ ```
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: knowledge-query
3
+ description: Answer a question from the knowledge base - find the relevant pages through the index, read them, answer with links to them, and file the answer back as a synthesis page when it is worth keeping.
4
+ ---
5
+
6
+ # Querying the knowledge base
7
+
8
+ The knowledge base exists so a question doesn't start from zero. Answer from it first; go back to the originals or the web only for what it doesn't hold.
9
+
10
+ 1. **Start from the index.** Read `index.md`, pick the pages that can matter, read those (not the whole knowledge base). `Grep` inside the knowledge base for terms and aliases the index doesn't reveal.
11
+ 2. **Answer from the pages**, linking each one you drew on. Say what comes from the knowledge base, what comes from an original in the sources folder (read it if the knowledge base is thin or contradictory) and what comes from outside (label it as such).
12
+ 3. **Say what is missing.** If the knowledge base can't answer part of the question, say so and name the source that would fill it, instead of filling the gap from memory silently.
13
+ 4. **File it back.** If the answer is a comparison, an analysis or a report that will be asked again, save it as `syntheses/<slug>.md` (template in `knowledge-pages`) with links to its inputs, add it to `index.md`, and log it: `## [date] query | <question>`. A quick factual answer needs no page.
14
+ 5. **Feed the knowledge base.** If answering revealed a concept or fact that has no page, or a contradiction, fix that in the knowledge base too and log it.
@@ -0,0 +1,132 @@
1
+ import type { AgentDefinition as SdkSubagentDefinition, McpServerConfig } from "@anthropic-ai/claude-agent-sdk";
2
+ /**
3
+ * The human-supervision spectrum every agent built on this kit shares, independent of
4
+ * domain: "interactive" pauses before every single action, "guided" only pauses before a
5
+ * hard-to-undo/visible-to-others action, "autonomous" has no human-in-the-loop channel at
6
+ * all. See session.ts's buildSessionOptions() for exactly what each mode changes.
7
+ *
8
+ * Deliberately orthogonal to whether the session is a one-shot run or a multi-turn chat
9
+ * (that's a matter of which entry point the caller uses — a single `query()` call vs.
10
+ * `runChatTui()`/`createInputQueue()` — not a supervision level): a concrete agent that
11
+ * wants to know "is this session chat-shaped" for its own purposes (e.g. picking a
12
+ * different system-prompt template) should track that as its own domain field on its
13
+ * config type, not conflate it with `Mode`.
14
+ */
15
+ export type Mode = "interactive" | "guided" | "autonomous";
16
+ /**
17
+ * The minimum a config object needs to drive `buildSessionOptions()` — a concrete agent's
18
+ * own config type (e.g. a `Config`) extends this with whatever domain fields
19
+ * it needs (a course URL, credentials, ...), which `buildSessionOptions()` itself never
20
+ * looks at directly: only `AgentSpec`'s methods receive the full concrete config.
21
+ */
22
+ export interface BaseSessionConfig {
23
+ mode: Mode;
24
+ /** Project root (the session's cwd): the folder under which the agent's notes, sources and runs live. */
25
+ projectDir: string;
26
+ /**
27
+ * Where the agent writes its own notes (the "wiki"). Setting this or `sourcesDir` is what
28
+ * gives the session the file tools (Read/Write/Edit/Glob/Grep, scoped — see
29
+ * hooks/fileScopeGate.ts); without either, the agent has no file access at all.
30
+ */
31
+ knowledgeDir?: string;
32
+ /**
33
+ * Original files, kept as obtained and apart from the notes in `knowledgeDir`: material
34
+ * the user drops in, plus whatever the agent saves with `save_to_sources` (downloaded
35
+ * documents, transcripts...). The agent can read and search it but never edit it — Write/
36
+ * Edit are scoped to `knowledgeDir` — and `save_to_sources` never overwrites.
37
+ */
38
+ sourcesDir?: string;
39
+ /** Directories besides `knowledgeDir`/`sourcesDir` where Write/Edit are allowed (see hooks/fileScopeGate.ts). */
40
+ extraWritableDirs?: string[];
41
+ /** Files or directories the agent must never read, search or write, e.g. a config file holding a password (see hooks/fileScopeGate.ts). */
42
+ deniedPaths?: string[];
43
+ /** Extra values (e.g. a password) to scrub out of the transcript log — see hooks/transcriptLogger.ts. */
44
+ secrets?: string[];
45
+ }
46
+ /**
47
+ * Everything actually *about the domain* that `buildSessionOptions()` needs but doesn't
48
+ * decide itself: which system prompt to build, which MCP servers to talk to besides the
49
+ * generic human-in-the-loop/knowledge ones this kit already wires up, which local plugin
50
+ * roots (skills/commands) to load, and which opt-in subagents (if any) to register.
51
+ *
52
+ * Deliberately not named `AgentDefinition`: the SDK already uses that name for a single
53
+ * subagent's own definition (`Options.agents: Record<string, AgentDefinition>`), and this
54
+ * is a level above that — it's what decides *which* subagents get registered, among other
55
+ * things.
56
+ */
57
+ export interface AgentSpec<TConfig extends BaseSessionConfig> {
58
+ /** The system prompt for this run — everything role/mode/domain-specific lives behind this call. */
59
+ buildSystemPrompt(config: TConfig): string;
60
+ /**
61
+ * MCP servers this agent always registers (e.g. Playwright for a browser-driving
62
+ * agent), on top of the generic ones `buildSessionOptions()` wires up itself when
63
+ * applicable (human approval, manual intervention, save-to-knowledge) — those aren't
64
+ * part of the spec because they're driven by `mode` plus this spec's own
65
+ * `manualInterventionTexts`/`knowledgeDir`/`sourcesDir`, not by anything else
66
+ * domain-specific.
67
+ */
68
+ buildMcpServers(config: TConfig, runDir: string): Record<string, McpServerConfig>;
69
+ /**
70
+ * Local plugin roots (skills/commands, SDK "local" plugin type) to load, in the order
71
+ * given, when the session has file tools (`config.knowledgeDir`/`config.sourcesDir`). Absolute paths; `buildSessionOptions()`
72
+ * doesn't know or care where they live on disk.
73
+ */
74
+ pluginRoots(config: TConfig): string[];
75
+ /**
76
+ * Opt-in subagents (the SDK's `Options.agents`) this spec wants registered for this
77
+ * config, plus which `subagent_type` values are therefore allowed to be spawned via the
78
+ * `Agent` tool (see hooks/subagentTypeGate.ts — the SDK's own built-in
79
+ * "general-purpose" type is always spawnable regardless of this list, which is exactly
80
+ * why that gate exists). Returns `undefined` when this config needs no subagents at
81
+ * all, so `buildSessionOptions()` knows not to grant `Agent`/`Bash` in the first place.
82
+ */
83
+ buildSubagents(config: TConfig): {
84
+ agents: Record<string, SdkSubagentDefinition>;
85
+ allowedSubagentTypes: string[];
86
+ } | undefined;
87
+ /**
88
+ * Tool names to explicitly block regardless of what `canUseTool`/`allowAnyMcpTool`
89
+ * would otherwise allow (e.g. a browser-automation agent blocking
90
+ * "mcp__playwright__browser_run_code_unsafe", which Microsoft's own description calls
91
+ * RCE-equivalent). Confirmed empirically that `disallowedTools` takes full precedence
92
+ * over a permissive `canUseTool` — a disallowed tool never even reaches that callback.
93
+ */
94
+ disallowedTools?: string[];
95
+ /** Overrides this kit's generic `save_to_sources` tool description (registered whenever `config.sourcesDir` is set) with domain-specific wording. */
96
+ saveToSourcesDescription?: string;
97
+ /**
98
+ * The built-in knowledge base (see knowledge.ts): when `config.knowledgeDir` is set, the kit
99
+ * appends its "Knowledge base" rules to the system prompt and loads its plugin (skills
100
+ * knowledge-pages/knowledge-ingest/knowledge-query/knowledge-lint, commands /knowledge:ingest, /knowledge:query,
101
+ * /knowledge:lint), so the agent maintains its notes as an interlinked wiki. On by default;
102
+ * set `false` for an agent that writes its own rules for `knowledgeDir` (or wants plain
103
+ * notes) — `knowledgePromptSection()`/`knowledgePluginRoot()` are exported to reuse the pieces.
104
+ */
105
+ knowledgeBase?: boolean;
106
+ /**
107
+ * Text for the generic human-approval checkpoint (see tools/humanApproval.ts) — what
108
+ * counts as "publishing something visible to others" is entirely domain-specific.
109
+ * Omit to use this kit's own generic, domain-neutral defaults.
110
+ */
111
+ humanApprovalTexts?: {
112
+ description: string;
113
+ approved: string;
114
+ rejected: string;
115
+ };
116
+ /**
117
+ * Text for the generic manual-intervention checkpoint (see tools/manualLogin.ts), AND
118
+ * this domain's opt-in signal for offering that checkpoint at all: `buildSessionOptions()`
119
+ * only registers `request_manual_login` when this is set (and `mode !== "autonomous"`).
120
+ * Manual intervention only makes sense for a domain that drives some live UI a human could
121
+ * actually step into by hand (a browser window, say) — there's no generic default to fall
122
+ * back to the way there is for `humanApprovalTexts` above, because this kit can't assume
123
+ * every agent built on it has such a UI at all. Leave unset for a domain that doesn't.
124
+ */
125
+ manualInterventionTexts?: {
126
+ toolDescription: string;
127
+ confirmedMessage: string;
128
+ checkpointTitle: string;
129
+ checkpointLines: string[];
130
+ checkpointQuestion?: string;
131
+ };
132
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ export interface ClaudeAuthConfig {
2
+ /** A previously-resolved token the caller already has (from wherever it stores one, if
3
+ * anywhere) — this module owns no persistence of its own, unlike an earlier version
4
+ * that read/wrote `~/.<appName>/config.json` itself (see git history). Sourcing this
5
+ * value across runs, if a concrete agent wants that at all, is entirely its own concern. */
6
+ claudeCodeOAuthToken?: string;
7
+ }
8
+ /**
9
+ * Pure lookup, no I/O and no console output of any kind — safe to call from a
10
+ * headless/non-interactive consumer (a server, an Electron main process) as much as from a
11
+ * terminal one.
12
+ *
13
+ * Checks, in order: `ANTHROPIC_API_KEY` (a complete authentication path on its own — API
14
+ * billing instead of subscription, so nothing else is checked when it's set),
15
+ * `CLAUDE_CODE_OAUTH_TOKEN`, then `config.claudeCodeOAuthToken` if the caller passed one.
16
+ * Returns `true` and (for the `config` case) sets `CLAUDE_CODE_OAUTH_TOKEN` on the process
17
+ * as a side effect once a token is found — the SDK's own subprocess reads that env var
18
+ * directly, never anything this kit passes it explicitly; `false` when none of the three
19
+ * has one. Getting a token in that case (e.g. by walking the user through
20
+ * `claude setup-token`) is a terminal-UX concern, not this function's — see
21
+ * `ensureClaudeAuth()` in tui/claudeAuth.ts, which calls this first and only falls back to
22
+ * that interactive flow when it returns `false`.
23
+ */
24
+ export declare function resolveClaudeAuth(config?: ClaudeAuthConfig): boolean;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Pure lookup, no I/O and no console output of any kind — safe to call from a
3
+ * headless/non-interactive consumer (a server, an Electron main process) as much as from a
4
+ * terminal one.
5
+ *
6
+ * Checks, in order: `ANTHROPIC_API_KEY` (a complete authentication path on its own — API
7
+ * billing instead of subscription, so nothing else is checked when it's set),
8
+ * `CLAUDE_CODE_OAUTH_TOKEN`, then `config.claudeCodeOAuthToken` if the caller passed one.
9
+ * Returns `true` and (for the `config` case) sets `CLAUDE_CODE_OAUTH_TOKEN` on the process
10
+ * as a side effect once a token is found — the SDK's own subprocess reads that env var
11
+ * directly, never anything this kit passes it explicitly; `false` when none of the three
12
+ * has one. Getting a token in that case (e.g. by walking the user through
13
+ * `claude setup-token`) is a terminal-UX concern, not this function's — see
14
+ * `ensureClaudeAuth()` in tui/claudeAuth.ts, which calls this first and only falls back to
15
+ * that interactive flow when it returns `false`.
16
+ */
17
+ export function resolveClaudeAuth(config = {}) {
18
+ if (process.env.ANTHROPIC_API_KEY)
19
+ return true;
20
+ if (process.env.CLAUDE_CODE_OAUTH_TOKEN)
21
+ return true;
22
+ if (config.claudeCodeOAuthToken) {
23
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = config.claudeCodeOAuthToken;
24
+ return true;
25
+ }
26
+ return false;
27
+ }
@@ -0,0 +1,33 @@
1
+ import type { HookCallback } from "@anthropic-ai/claude-agent-sdk";
2
+ /**
3
+ * Where the built-in file tools may act. Without this, the only boundary is the SDK's own
4
+ * working-directory scope — the whole project directory — so keeping the agent out of the
5
+ * user's own files (a config file holding a password, the originals in sources/) would rest on the system
6
+ * prompt alone.
7
+ */
8
+ export interface FileScope {
9
+ /** Base for relative paths: the session's cwd. */
10
+ projectDir: string;
11
+ /** Write/Edit are only allowed inside these. */
12
+ writableDirs: string[];
13
+ /** Readable and searchable but never writable; only affects the wording of the denial. */
14
+ readOnlyDirs?: string[];
15
+ /** Grep is only allowed inside these — it prints file contents, so it isn't let loose on the whole project. */
16
+ searchableDirs: string[];
17
+ /** Never readable, searchable or writable. */
18
+ deniedPaths: string[];
19
+ }
20
+ /** Whether `candidate` is `base` itself or somewhere inside it (case-insensitive on Windows, like path.relative). */
21
+ export declare function isWithin(base: string, candidate: string): boolean;
22
+ /**
23
+ * The reason to deny `toolName` with `input` under `scope`, or `undefined` to let it
24
+ * through. Tools other than Read/Write/Edit/Grep are never judged here, and a call
25
+ * without a path is left for the tool itself to reject.
26
+ */
27
+ export declare function checkFileScope(scope: FileScope, toolName: string, input: Record<string, unknown>): string | undefined;
28
+ /**
29
+ * PreToolUse hook enforcing `scope` on Read/Write/Edit/Grep, for the main agent and its
30
+ * subagents alike. Bash, when a subagent has it, is not covered: it can reach any path,
31
+ * which is why Bash-granting features stay opt-in.
32
+ */
33
+ export declare function createFileScopeGate(scope: FileScope): HookCallback;