kc-beta 0.2.1 → 0.3.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 (44) hide show
  1. package/QUICKSTART.md +149 -0
  2. package/README.md +207 -0
  3. package/package.json +12 -2
  4. package/src/agent/context.js +8 -4
  5. package/src/agent/engine.js +154 -9
  6. package/src/agent/pipelines/initializer.js +53 -8
  7. package/src/agent/session-state.js +1 -0
  8. package/src/agent/skill-loader.js +13 -1
  9. package/src/agent/task-manager.js +186 -0
  10. package/src/agent/tools/document-parse.js +99 -21
  11. package/src/agent/tools/document-search.js +24 -8
  12. package/src/agent/tools/sandbox-exec.js +16 -5
  13. package/src/agent/tools/workspace-file.js +47 -20
  14. package/src/agent/workspace.js +24 -1
  15. package/src/cli/components.js +42 -1
  16. package/src/cli/config.js +100 -6
  17. package/src/cli/index.js +39 -2
  18. package/src/cli/onboard.js +70 -1
  19. package/src/config.js +43 -3
  20. package/src/model-tiers.json +153 -0
  21. package/src/providers.js +63 -66
  22. package/template/AGENT.md +20 -0
  23. package/template/skills/en/meta/compliance-judgment/SKILL.md +10 -42
  24. package/template/skills/en/meta/document-chunking/SKILL.md +32 -0
  25. package/template/skills/en/meta/document-parsing/SKILL.md +11 -18
  26. package/template/skills/en/meta/entity-extraction/SKILL.md +13 -28
  27. package/template/skills/en/meta/tree-processing/SKILL.md +19 -1
  28. package/template/skills/en/meta-meta/auto-model-selection/SKILL.md +53 -0
  29. package/template/skills/en/meta-meta/pdf-review-dashboard/SKILL.md +57 -0
  30. package/template/skills/en/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
  31. package/template/skills/en/meta-meta/rule-extraction/SKILL.md +24 -1
  32. package/template/skills/en/meta-meta/skill-authoring/SKILL.md +6 -0
  33. package/template/skills/en/meta-meta/skill-to-workflow/SKILL.md +4 -0
  34. package/template/skills/zh/meta/compliance-judgment/SKILL.md +41 -262
  35. package/template/skills/zh/meta/document-chunking/SKILL.md +32 -0
  36. package/template/skills/zh/meta/document-parsing/SKILL.md +65 -132
  37. package/template/skills/zh/meta/entity-extraction/SKILL.md +68 -230
  38. package/template/skills/zh/meta/tree-processing/SKILL.md +82 -194
  39. package/template/skills/zh/meta-meta/auto-model-selection/SKILL.md +51 -0
  40. package/template/skills/zh/meta-meta/pdf-review-dashboard/SKILL.md +55 -0
  41. package/template/skills/zh/meta-meta/pdf-review-dashboard/scripts/generate_review.js +262 -0
  42. package/template/skills/zh/meta-meta/rule-extraction/SKILL.md +79 -164
  43. package/template/skills/zh/meta-meta/skill-authoring/SKILL.md +64 -185
  44. package/template/skills/zh/meta-meta/skill-to-workflow/SKILL.md +95 -216
package/QUICKSTART.md ADDED
@@ -0,0 +1,149 @@
1
+ # KC Agent CLI (Beta) — Quickstart
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ npm install -g kc-beta
7
+ ```
8
+
9
+ Requires **Node.js 20+**.
10
+
11
+ ## Setup
12
+
13
+ Run the onboarding wizard to configure your LLM provider and API keys:
14
+
15
+ ```bash
16
+ kc-beta onboard
17
+ ```
18
+
19
+ You'll be prompted to choose:
20
+
21
+ 1. **Language** — English or 中文
22
+ 2. **LLM Provider** — SiliconFlow, Aliyun Bailian, Anthropic, OpenAI, VolcanoCloud, Zhipu GLM, MiniMax, OpenRouter, or custom
23
+ 3. **API Key** — your provider API key (supports both API keys and Aliyun/VolcanoCloud coding plan keys)
24
+ 4. **Model Discovery** — KC auto-discovers available models via API or curated lists and suggests tier assignments with capability-based ranking
25
+ 5. **Conductor Model** — the main model that drives the agent
26
+ 6. **Worker LLM Tiers** — tier1 (best) through tier4 (cheapest) for verification tasks
27
+ 7. **VLM Tiers** — vision models for OCR/document parsing (tier1-3)
28
+ 8. **Worker Provider** (optional) — use a different provider for worker LLMs (defaults to conductor provider)
29
+
30
+ Config is saved to `~/.kc_agent/config.json` and shared across projects.
31
+
32
+ ### Edit Settings Later
33
+
34
+ ```bash
35
+ kc-beta config
36
+ ```
37
+
38
+ Category-based editor for: LLM provider, model tiers, VLM tiers, worker LLM provider, quality thresholds, language.
39
+
40
+ ## Create a Project
41
+
42
+ ```bash
43
+ kc-beta init my-project
44
+ kc-beta init my-project --lang=zh # Chinese skills
45
+ ```
46
+
47
+ This creates a workspace with:
48
+
49
+ ```
50
+ my-project/
51
+ .env # Project-level config (overrides global)
52
+ Rules/ # Put regulation documents here
53
+ Samples/ # Put sample documents here
54
+ Input/ # Production batches
55
+ Output/ # Verification results
56
+ skills/ # Meta-methodology skills (en or zh)
57
+ ```
58
+
59
+ ## Start the Agent
60
+
61
+ ```bash
62
+ kc-beta # default language from config
63
+ kc-beta --en # this session in English (does not change config)
64
+ kc-beta --zh # this session in Chinese (does not change config)
65
+ ```
66
+
67
+ Launch from your project directory — KC has full read/write access to the folder you launch from:
68
+
69
+ ```bash
70
+ cd my-project
71
+ kc-beta
72
+ ```
73
+
74
+ The agent starts in **BOOTSTRAP** phase. It will:
75
+
76
+ 1. Set up the workspace structure
77
+ 2. Detect regulations and samples in your project directory
78
+ 3. Ask about your verification scenario
79
+
80
+ Once regulations and samples are in place, the agent advances through 6 phases automatically:
81
+
82
+ | Phase | What happens |
83
+ |-------|-------------|
84
+ | **BOOTSTRAP** | Workspace setup, understand the scenario |
85
+ | **EXTRACTION** | Decompose regulations into atomic rules |
86
+ | **SKILL_AUTHORING** | Write verification skills for each rule |
87
+ | **SKILL_TESTING** | Test skills, iterate via evolution loop |
88
+ | **DISTILLATION** | Convert skills to worker LLM workflows |
89
+ | **PRODUCTION_QC** | Run workflows on production docs with QC |
90
+
91
+ ## Slash Commands
92
+
93
+ | Command | Description |
94
+ |---------|-------------|
95
+ | `/help` | Show available commands |
96
+ | `/status` | Session info, model, phase, context usage |
97
+ | `/clear` | Clear conversation history |
98
+ | `/compact` | Summarize older messages to reduce context usage |
99
+ | `/sessions` | List all sessions |
100
+ | `/resume <name>` | Resume a previous session (restores phase + pipeline state) |
101
+ | `/rename <name>` | Rename current session |
102
+ | `/exit` | Save state and quit |
103
+
104
+ ## Keyboard Shortcuts
105
+
106
+ - **Enter** — Send message
107
+ - **Ctrl+C** — Clear queue (if streaming) or save & exit
108
+ - **Ctrl+D** — Save & exit
109
+
110
+ ## Status Bar
111
+
112
+ The status bar shows:
113
+ - Session ID and current phase
114
+ - **Context usage**: `CTX: 45.2k/200k (23%)` — turns green/yellow/red as context fills
115
+
116
+ ## Per-Project Config
117
+
118
+ Override global settings in your project's `.env`:
119
+
120
+ ```env
121
+ LLM_API_KEY=sk-xxx
122
+ LLM_BASE_URL=https://api.siliconflow.cn/v1
123
+
124
+ TIER1=Pro/zai-org/GLM-5
125
+ TIER2=
126
+ TIER3=
127
+ TIER4=
128
+
129
+ SKILL_ACCURACY=0.9
130
+ WORKFLOW_ACCURACY=0.9
131
+ MAX_ITERATIONS=20
132
+
133
+ # Optional: web search via Tavily
134
+ TAVILY_API_KEY=tvly-xxx
135
+ ```
136
+
137
+ Legacy keys (`SILICONFLOW_API_KEY`, `SILICONFLOW_BASE_URL`) are still accepted for backward compatibility.
138
+
139
+ ## Web Search
140
+
141
+ KC can search the web using Tavily when information is not available in your provided documents. Set `TAVILY_API_KEY` in your `.env` or global config. KC prioritizes your domain documents over web results.
142
+
143
+ ## Troubleshooting
144
+
145
+ - **"No API key configured"** — Run `kc-beta onboard` first
146
+ - **Connection errors** — Check your API key and base URL. KC retries up to 10 times with exponential backoff on transient failures.
147
+ - **Context too long** — Use `/compact` to summarize older messages, or let automatic windowing handle it
148
+ - **Resume after crash** — Use `/resume <session-name>` to pick up where you left off
149
+ - **Node version** — Requires Node.js 20+. Check with `node --version`
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # KC Agent CLI (`kc-beta`)
2
+
3
+ > Build, distill, and run document verification systems with an LLM agent.
4
+ > Pure Node.js. One binary. Bring your own model.
5
+
6
+ KC is a coding agent purpose-built for **rule-based document verification**:
7
+ read a regulation, decompose it into atomic verification rules, write skills
8
+ to check each rule against sample documents, and (optionally) distill those
9
+ skills into cheap worker-LLM workflows for production batch processing.
10
+
11
+ It is designed for the developer at a bank, insurer, or law firm who needs
12
+ to verify hundreds of documents against dozens of compliance rules — and
13
+ wants the system to be transparent, testable, and ownable.
14
+
15
+ ---
16
+
17
+ ## Quick Install
18
+
19
+ ```bash
20
+ npm install -g kc-beta
21
+ kc-beta onboard # configure provider + API key
22
+ cd my-project # a folder containing rules/ and samples/
23
+ kc-beta # launch the agent
24
+ ```
25
+
26
+ Requires **Node.js 20+**. See [QUICKSTART.md](./QUICKSTART.md) for the full setup walkthrough.
27
+
28
+ ---
29
+
30
+ ## What It Does
31
+
32
+ KC drives a single coding agent through six phases:
33
+
34
+ | Phase | What it does |
35
+ |-------|-------------|
36
+ | **BOOTSTRAP** | Set up the workspace, detect rules/samples in your project |
37
+ | **EXTRACTION** | Decompose regulation documents into atomic, testable rules |
38
+ | **SKILL_AUTHORING** | Write a verification skill for each rule (Anthropic skill-creator format) |
39
+ | **SKILL_TESTING** | Run skills on samples, iterate via the evolution loop |
40
+ | **DISTILLATION** | Convert proven skills into cheap worker-LLM workflows |
41
+ | **PRODUCTION_QC** | Run workflows on production batches with confidence-based sampling |
42
+
43
+ The conductor LLM (your main model) drives all reasoning. Worker LLM tools
44
+ are gated to DISTILL phases only, so the build phase is always grounded in
45
+ high-quality output.
46
+
47
+ ---
48
+
49
+ ## Architecture
50
+
51
+ ```
52
+ ~/.kc_agent/
53
+ config.json # provider, API key, model tiers
54
+ workspaces/<sessionId>/ # KC's working files
55
+ rules/, rule_skills/, workflows/, samples/, output/, logs/
56
+ AGENT.md # per-project context (KC can edit)
57
+ tasks.json # ralph-loop task list
58
+ session-state.json # phase + pipeline state for /resume
59
+
60
+ your-project/ # where you launched kc-beta
61
+ rules/ # source regulations (KC reads with scope="project")
62
+ samples/ # sample documents
63
+ Output/ # KC writes user-facing reports here
64
+ ```
65
+
66
+ **Dual-directory design.** KC has full read/write to its own workspace plus
67
+ *scoped* read/write to your project directory. Source files stay in your
68
+ project; KC's working artifacts stay in `~/.kc_agent/workspaces/`.
69
+
70
+ **Phase-gated tools.** Worker LLM, workflow runner, tier downgrade, and QC
71
+ sampling tools only register during DISTILL phases. BUILD phases force the
72
+ conductor to do the intellectual work directly — the results are the
73
+ ground-truth baseline for distillation.
74
+
75
+ **Skills as first-class deliverables.** Every rule produces a self-contained
76
+ skill folder (SKILL.md + scripts + references + samples). For complex rules
77
+ that worker LLMs can't reliably handle, the skill itself — run by a capable
78
+ agent — is the production solution.
79
+
80
+ ---
81
+
82
+ ## Provider Support
83
+
84
+ 10 providers configured out of the box:
85
+
86
+ - **SiliconFlow** (default, recommended for China)
87
+ - **Aliyun Bailian** (with coding-plan key support)
88
+ - **VolcanoCloud** (ByteDance Doubao)
89
+ - **Anthropic** (Messages API native)
90
+ - **OpenAI**
91
+ - **Zhipu GLM**
92
+ - **MiniMax**
93
+ - **OpenRouter**
94
+ - **AWS Bedrock** (stub)
95
+ - **Custom** (any OpenAI-compatible endpoint)
96
+
97
+ Model assignments live in [`src/model-tiers.json`](./src/model-tiers.json) —
98
+ edit directly to update tier-1 through tier-4 LLM and tier-1 through tier-3
99
+ VLM (vision) models per provider, no code changes needed.
100
+
101
+ You can use **separate providers** for the conductor and worker LLMs (e.g.,
102
+ Anthropic conductor + SiliconFlow workers).
103
+
104
+ ---
105
+
106
+ ## Ralph-Loop Autonomous Execution
107
+
108
+ When KC extracts rules, it automatically generates a per-rule task list and
109
+ processes them one at a time. Between tasks the conductor's context is
110
+ compacted aggressively, so context stays bounded even with 50+ rules.
111
+
112
+ ```
113
+ SKILL_AUTHORING [████████░░░░] 8/12
114
+ ✓ R001 Registered capital check
115
+ ✓ R002 Net asset adequacy
116
+ ▸ R003 Related-party disclosure ← current
117
+ · R004 Risk capital calculation
118
+ ...
119
+ ```
120
+
121
+ Use `/tasks` to see the full list. The agent decides *how* to do each task;
122
+ the task manager only tells it *what's next*.
123
+
124
+ ---
125
+
126
+ ## Slash Commands
127
+
128
+ ```
129
+ /help Show available commands
130
+ /status Session, model, phase, context usage
131
+ /tasks Show task list and progress
132
+ /clear Clear conversation (workspace preserved)
133
+ /compact Summarize older messages via the conductor
134
+ /sessions List all sessions
135
+ /resume <name> Resume a previous session
136
+ /rename <name> Rename current session
137
+ /exit Save state and quit
138
+ ```
139
+
140
+ `--en` / `--zh` flags override language for one session without writing config.
141
+
142
+ ---
143
+
144
+ ## Optional Plugins
145
+
146
+ Some heavyweight features ship as **meta-meta skills** the agent invokes on
147
+ demand, rather than always-on dependencies:
148
+
149
+ - **`pdf-review-dashboard`** — Two-column HTML dashboard (PDF on the left,
150
+ verification results on the right, click-to-jump) for manual review and
151
+ ground-truth collection.
152
+ - **`auto-model-selection`** — Use [Context7](https://github.com/upstash/context7)
153
+ CLI to fetch current model listings when the bundled `model-tiers.json`
154
+ is stale or you've switched providers.
155
+
156
+ Both are bundled in `template/skills/{en,zh}/meta-meta/` and discovered by
157
+ the skill loader at startup.
158
+
159
+ ---
160
+
161
+ ## Configuration
162
+
163
+ Global config: `~/.kc_agent/config.json` (set by `kc-beta onboard`).
164
+ Per-project override: `<project>/.env`.
165
+
166
+ Edit anytime with the category-based editor:
167
+
168
+ ```bash
169
+ kc-beta config
170
+ ```
171
+
172
+ Categories: LLM Provider, Model Tiers, VLM Tiers, Worker LLM Provider,
173
+ Quality Thresholds, Language.
174
+
175
+ ---
176
+
177
+ ## Documentation
178
+
179
+ - [QUICKSTART.md](./QUICKSTART.md) — full setup and slash command reference
180
+ - [DEV_LOG.md](./DEV_LOG.md) — release history and design rationale
181
+ - [docs/global_update_design_v3.md](./docs/global_update_design_v3.md) — v3 design plan and progress tracker
182
+ - [docs/initial_spec_draft.md](./docs/initial_spec_draft.md) — original architectural spec
183
+
184
+ ---
185
+
186
+ ## Status
187
+
188
+ **v0.3.1 — beta.** Production-readiness update covering the seven blocks
189
+ of the v3 design plan: dual-directory permissions, AGENT.md per-project
190
+ context, PDF review dashboard skill, parsing/extraction skill rewrites,
191
+ production-experience meta-skill polish, model-tier baseline + Context7
192
+ plugin, and ralph-loop autonomous task execution.
193
+
194
+ We are inviting a small group of developer users to test before public launch.
195
+ Bug reports and PRs welcome at <https://github.com/kitchen-engineer42/kc-cli>.
196
+
197
+ ---
198
+
199
+ ## License
200
+
201
+ MIT. Bundled meta-skills under `template/skills/` are proprietary —
202
+ distributed via npm but not open-source. See `template/skills/LICENSE` for
203
+ terms.
204
+
205
+ ---
206
+
207
+ *Built by Memium / kitchen-engineer42.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kc-beta",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "KC Agent — LLM document verification agent (pure Node.js CLI)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,8 +9,18 @@
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
- "template/"
12
+ "template/",
13
+ "README.md",
14
+ "QUICKSTART.md"
13
15
  ],
16
+ "homepage": "https://github.com/kitchen-engineer42/kc-cli",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/kitchen-engineer42/kc-cli.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/kitchen-engineer42/kc-cli/issues"
23
+ },
14
24
  "engines": {
15
25
  "node": ">=20.0.0"
16
26
  },
@@ -32,9 +32,11 @@ outcome. Handle ambiguity explicitly — note it, ask the developer user. After
32
32
  audit which regulation sections are not yet covered.
33
33
 
34
34
  ### Entity Extraction
35
- Prefer regex/Python for predictable formats. Use LLM only when semantic understanding \
36
- is required. Every extraction captures: value, evidence, source location, confidence, \
37
- method used.
35
+ Choose the cheapest method that meets accuracy threshold. Regex is the smallest \
36
+ "model" zero cost, instant, deterministic. Worker LLM handles semantic tasks \
37
+ regex cannot (contextual interpretation, misleading language, adequacy judgment). \
38
+ Try different methods, find the cost-accuracy balance. Every extraction captures: \
39
+ value, evidence, source location, confidence, method used.
38
40
 
39
41
  ### Skill Authoring
40
42
  Write each rule into a skill folder following the Anthropic skill-creator format. A \
@@ -79,13 +81,15 @@ unclear regulations with them. Present results and let them judge.`;
79
81
  export class ContextAssembler {
80
82
  /**
81
83
  * @param {object} [opts]
84
+ * @param {string} [opts.agentMd] - Content of workspace AGENT.md (per-project context)
82
85
  * @param {string} [opts.pipelineState]
83
86
  * @param {string} [opts.workspaceState]
84
87
  * @param {string} [opts.skillIndex] - Brief index of available meta skills
85
88
  * @returns {string}
86
89
  */
87
- build({ pipelineState, workspaceState, skillIndex } = {}) {
90
+ build({ agentMd, pipelineState, workspaceState, skillIndex } = {}) {
88
91
  const parts = [AGENT_IDENTITY];
92
+ if (agentMd) parts.push(agentMd);
89
93
  if (skillIndex) parts.push(skillIndex);
90
94
  if (pipelineState) parts.push(pipelineState);
91
95
  if (workspaceState) parts.push(workspaceState);
@@ -1,3 +1,5 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
1
3
  import { AgentEvent } from "./events.js";
2
4
  import { ContextAssembler } from "./context.js";
3
5
  import { ConversationHistory } from "./history.js";
@@ -20,6 +22,7 @@ import { TierDowngradeTool } from "./tools/tier-downgrade.js";
20
22
  import { AgentTool } from "./tools/agent-tool.js";
21
23
  import { WebSearchTool } from "./tools/web-search.js";
22
24
  import { SkillLoader } from "./skill-loader.js";
25
+ import { TaskManager } from "./task-manager.js";
23
26
  import { Phase } from "./pipelines/index.js";
24
27
  import { ProjectInitializer } from "./pipelines/initializer.js";
25
28
  import { RuleExtractionPipeline } from "./pipelines/extraction.js";
@@ -56,7 +59,7 @@ export class AgentEngine {
56
59
  this.context = new ContextAssembler();
57
60
 
58
61
  // Workspace + structural components
59
- this.workspace = new Workspace(config.kcWorkspaceRoot, sessionId);
62
+ this.workspace = new Workspace(config.kcWorkspaceRoot, sessionId, config.projectDir);
60
63
  this.history = new ConversationHistory(this.workspace.cwd);
61
64
  this.versionManager = new VersionManager(this.workspace.cwd);
62
65
  this.cornerCases = new CornerCaseRegistry(this.workspace.cwd);
@@ -74,6 +77,9 @@ export class AgentEngine {
74
77
  // Session state persistence
75
78
  this.sessionState = new SessionState(this.workspace.cwd);
76
79
 
80
+ // Task manager (ralph-loop)
81
+ this.taskManager = new TaskManager(this.workspace.cwd);
82
+
77
83
  // Build all tool instances (but register phase-appropriate ones)
78
84
  this._buildTools = this._createAllTools();
79
85
  this._phaseSummaries = [];
@@ -102,12 +108,20 @@ export class AgentEngine {
102
108
  * re-register per phase without recreating.
103
109
  */
104
110
  _createAllTools() {
111
+ // Worker LLM uses separate config if set, otherwise falls back to conductor
112
+ const workerApiKey = this.config.effectiveWorkerApiKey();
113
+ const workerBaseUrl = this.config.effectiveWorkerBaseUrl();
114
+ const workerAuthType = this.config.effectiveWorkerAuthType();
115
+
105
116
  const workerLlm = new WorkerLLMCallTool(this.workspace, {
106
- apiKey: this.config.llmApiKey,
107
- baseUrl: this.config.llmBaseUrl,
108
- authType: this.config.authType,
117
+ apiKey: workerApiKey,
118
+ baseUrl: workerBaseUrl,
119
+ authType: workerAuthType,
109
120
  });
110
121
 
122
+ // OCR/VLM uses worker config (VLM is a type of worker LLM)
123
+ const vlmModel = this.config.vlmTier1 || "";
124
+
111
125
  return {
112
126
  // Always available (BUILD + DISTILL)
113
127
  core: [
@@ -116,9 +130,9 @@ export class AgentEngine {
116
130
  new DocumentParseTool(this.workspace, {
117
131
  mineruApiUrl: this.config.mineruApiUrl,
118
132
  mineruApiKey: this.config.mineruApiKey,
119
- llmApiKey: this.config.llmApiKey,
120
- llmBaseUrl: this.config.llmBaseUrl,
121
- ocrModel: this.config.ocrModelTier1,
133
+ llmApiKey: workerApiKey,
134
+ llmBaseUrl: workerBaseUrl,
135
+ ocrModel: vlmModel,
122
136
  }),
123
137
  new DocumentSearchTool(this.workspace),
124
138
  new RuleCatalogTool(this.workspace),
@@ -156,15 +170,57 @@ export class AgentEngine {
156
170
  }
157
171
  }
158
172
 
173
+ /**
174
+ * Read AGENT.md from workspace (per-project context).
175
+ * Returns content string or empty string if not found.
176
+ */
177
+ _readAgentMd() {
178
+ const agentMdPath = path.join(this.workspace.cwd, "AGENT.md");
179
+ try {
180
+ if (fs.existsSync(agentMdPath)) {
181
+ return fs.readFileSync(agentMdPath, "utf-8");
182
+ }
183
+ } catch { /* ignore */ }
184
+ return "";
185
+ }
186
+
187
+ /**
188
+ * Build the workspace/project directory state string for the system prompt.
189
+ */
190
+ _buildWorkspaceState() {
191
+ const lines = [
192
+ `## Directory Layout`,
193
+ `**KC Workspace:** ${this.workspace.cwd}`,
194
+ ` Use scope="workspace" (default). Write all working files here (rules, skills, workflows, results, logs).`,
195
+ ];
196
+ if (this.workspace.projectDir) {
197
+ lines.push(
198
+ `**Project Directory:** ${this.workspace.projectDir}`,
199
+ ` Use scope="project" to read/write files in the user's project folder.`,
200
+ ` This is where the user's source regulations, samples, and reference documents are.`,
201
+ ``,
202
+ `Read source documents from the project directory. Write KC outputs to the workspace.`,
203
+ `Write user-facing exports (reports, results) to the project directory when the user asks.`,
204
+ );
205
+ }
206
+
207
+ // Task progress (ralph-loop)
208
+ const taskContext = this.taskManager.describeForContext();
209
+ if (taskContext) lines.push("", taskContext);
210
+
211
+ return lines.join("\n");
212
+ }
213
+
159
214
  /**
160
215
  * Get current context usage statistics.
161
216
  * @returns {{ totalTokens: number, limit: number, percentage: number }}
162
217
  */
163
218
  getContextStats() {
164
219
  const systemPrompt = this.context.build({
220
+ agentMd: this._readAgentMd(),
165
221
  skillIndex: this._skillLoader.formatForContext(),
166
222
  pipelineState: this.pipelines[this.currentPhase]?.describeState?.() || null,
167
- workspaceState: `Your workspace directory is: ${this.workspace.cwd}`,
223
+ workspaceState: this._buildWorkspaceState(),
168
224
  });
169
225
  const systemTokens = estimateTokens(systemPrompt);
170
226
  const messageTokens = estimateMessagesTokens(this.history.messages);
@@ -270,6 +326,14 @@ export class AgentEngine {
270
326
  engine._phaseSummaries = data.phaseSummaries || [];
271
327
  engine._registerToolsForPhase(engine.currentPhase);
272
328
 
329
+ // Restore project directory from saved state
330
+ if (data.projectDir) {
331
+ if (fs.existsSync(data.projectDir)) {
332
+ engine.workspace.projectDir = data.projectDir;
333
+ }
334
+ // If dir no longer exists, projectDir stays as whatever was passed at launch
335
+ }
336
+
273
337
  // Restore pipeline milestones
274
338
  const milestones = data.pipelineMilestones || {};
275
339
  for (const [phase, mData] of Object.entries(milestones)) {
@@ -309,9 +373,10 @@ export class AgentEngine {
309
373
  const pipelineState = pipeline?.describeState?.() || null;
310
374
 
311
375
  const systemPrompt = this.context.build({
376
+ agentMd: this._readAgentMd(),
312
377
  skillIndex: this._skillLoader.formatForContext(),
313
378
  pipelineState,
314
- workspaceState: `Your workspace directory is: ${this.workspace.cwd}`,
379
+ workspaceState: this._buildWorkspaceState(),
315
380
  });
316
381
  const tools = this.toolRegistry.schemasOpenai();
317
382
 
@@ -433,6 +498,10 @@ export class AgentEngine {
433
498
  });
434
499
  this.currentPhase = pEvent.nextPhase;
435
500
  this._registerToolsForPhase(this.currentPhase);
501
+
502
+ // Ralph-loop: create per-rule tasks for the new phase
503
+ this._createTasksForPhase(this.currentPhase);
504
+
436
505
  this.saveState();
437
506
  }
438
507
  yield new AgentEvent({
@@ -450,4 +519,80 @@ export class AgentEngine {
450
519
  }
451
520
  }
452
521
  }
522
+
523
+ /**
524
+ * Create per-rule tasks when entering a new phase.
525
+ * Reads the rule catalog and creates one task per rule for the given phase.
526
+ */
527
+ _createTasksForPhase(phase) {
528
+ const catalogPath = path.join(this.workspace.cwd, "rules", "catalog.json");
529
+ if (!fs.existsSync(catalogPath)) return;
530
+
531
+ try {
532
+ const catalog = JSON.parse(fs.readFileSync(catalogPath, "utf-8"));
533
+ const rules = Array.isArray(catalog) ? catalog : [];
534
+ if (rules.length > 0) {
535
+ this.taskManager.createRuleTasks(rules, phase);
536
+ }
537
+ } catch { /* skip if catalog can't be read */ }
538
+ }
539
+
540
+ /**
541
+ * Ralph-loop: run a turn, then auto-continue through pending tasks.
542
+ * Compacts context aggressively between tasks to prevent context blowup.
543
+ * If no tasks exist, behaves identically to runTurn().
544
+ *
545
+ * @param {string} userMessage
546
+ * @yields {AgentEvent}
547
+ */
548
+ async *runTaskLoop(userMessage) {
549
+ // Run the initial turn (user's request)
550
+ yield* this.runTurn(userMessage);
551
+
552
+ // Auto-continue through pending tasks
553
+ while (this.taskManager.getNextPending()) {
554
+ // Context safety: force compaction if above 70%, or light compaction if history is long
555
+ const stats = this.getContextStats();
556
+ if (stats.percentage > 70) {
557
+ await this.compact();
558
+ } else if (this.history.messages.length > 15) {
559
+ await this.compact({ recentCount: 8 });
560
+ }
561
+
562
+ const task = this.taskManager.getNextPending();
563
+ this.taskManager.updateTask(task.id, { status: "in_progress" });
564
+
565
+ // Yield task progress event for TUI
566
+ yield new AgentEvent({
567
+ type: "task_progress",
568
+ data: {
569
+ taskId: task.id,
570
+ title: task.title,
571
+ ruleId: task.ruleId,
572
+ status: "in_progress",
573
+ progress: this.taskManager.progress,
574
+ },
575
+ });
576
+
577
+ // Synthesize a task-focused prompt
578
+ const taskPrompt = `Continue with next task: ${task.title}` +
579
+ (task.ruleId ? ` (rule: ${task.ruleId})` : "");
580
+
581
+ yield* this.runTurn(taskPrompt);
582
+
583
+ this.taskManager.updateTask(task.id, { status: "completed" });
584
+ this.taskManager.save();
585
+ this.saveState();
586
+
587
+ yield new AgentEvent({
588
+ type: "task_progress",
589
+ data: {
590
+ taskId: task.id,
591
+ title: task.title,
592
+ status: "completed",
593
+ progress: this.taskManager.progress,
594
+ },
595
+ });
596
+ }
597
+ }
453
598
  }