@minhpnq1807/contextos 0.6.3 → 0.6.4

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.4
4
+
5
+ - **Project context generator:** Added `ctx doctor --fix` and `ctx setup --generate-project-context` to explicitly scaffold starter project skills and a primary workflow when a repository has rules but is missing ContextOS-ready skills/workflows. Generation is repo-scoped, does not run from `npm install`, and does not overwrite existing files unless `--force` is passed to `ctx doctor --fix`.
6
+
3
7
  ## 0.6.3
4
8
 
5
9
  - **Launch benchmark wording:** Clarified that `ctx leaderboard --hallucination` is an offline deterministic benchmark comparing a raw heuristic baseline with ContextOS evidence-based context selection, while live agent results remain pending external CLI environments.
package/README.md CHANGED
@@ -1,109 +1,45 @@
1
1
  # ContextOS
2
2
 
3
- Stop coding agents from ignoring repo rules, guessing the wrong path, and reading random files.
3
+ Same prompt. Same model. Different context.
4
4
 
5
- ContextOS gives the agent the right rules, files, skills, workflows, and evidence before it writes code.
5
+ ContextOS stops coding agents from ignoring repo rules, guessing the wrong path, and reading random files.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@minhpnq1807/contextos.svg)](https://www.npmjs.com/package/@minhpnq1807/contextos)
8
8
  [![CI](https://github.com/khovan123/contextOS/actions/workflows/ci.yml/badge.svg)](https://github.com/khovan123/contextOS/actions/workflows/ci.yml)
9
- [![ContextOS Ready](https://img.shields.io/badge/ContextOS-Ready_Gold-2ea44f)](#contextos-ready)
10
9
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
10
 
12
11
  ```text
13
- Problem: Agents ignore project rules.
14
- Fix: ContextOS puts the relevant AGENTS.md rules in front of the agent for this task.
12
+ Prompt:
13
+ Fix deployment
15
14
 
16
- Problem: Agents choose the wrong deployment path.
17
- Fix: ContextOS checks repo evidence before suggesting skills like EAS, Vercel, Docker, or CI/CD.
15
+ Raw Agent:
16
+ Vercel
17
+ ❌ Docker
18
+ ❌ Railway
18
19
 
19
- Problem: Agents grep random files.
20
- Fix: ContextOS suggests the files and workflows to check first.
20
+ ContextOS:
21
+ EAS
22
+ ✅ Mobile Deployment
23
+ ✅ GitHub Actions
21
24
  ```
22
25
 
23
- ContextOS is not another `AGENTS.md` loader. It is a pre-flight context layer for coding agents: it turns repo rules, project signals, skills, workflows, and evidence into a compact task brief before the agent starts editing.
26
+ ContextOS reads the repo before the agent starts: project rules, repo evidence, suggested files, skills, workflows, and post-task proof.
24
27
 
25
28
  Published package: [`@minhpnq1807/contextos`](https://www.npmjs.com/package/@minhpnq1807/contextos)
26
29
 
27
- ## Demo
28
-
29
- ![ContextOS demo: same prompt, different repo, correct skills](docs/demo/same-prompt-different-context.gif)
30
-
31
- Same prompt. Same model. Different context.
32
-
33
- ```bash
34
- ctx skills doctor -- "fix deployed"
35
- ```
36
-
37
- | Repo evidence | What ContextOS tells the agent |
38
- | --- | --- |
39
- | `eas.json`, `expo`, `react-native` | `eas`, `mobile-deployment`, `github-actions-ci-cd` |
40
- | `vercel.json`, `next`, GitHub workflow | `vercel-deployment`, `github-actions-ci-cd`, `env-secret-management` |
41
- | ContextOS repo with no app deploy evidence | no deployment skill selected |
42
-
43
- More 10-second demos:
44
-
45
- | Demo | GIF |
46
- | --- | --- |
47
- | AGENTS.md Lost In The Middle | [docs/demo/agents-lost-middle.gif](docs/demo/agents-lost-middle.gif) |
48
- | ContextOS Ready Gold | [docs/demo/contextos-ready.gif](docs/demo/contextos-ready.gif) |
49
-
50
- Regenerate the GIFs from real local `ctx` command output:
51
-
52
- ```bash
53
- npm run demo:capture
54
- ```
55
-
56
- ## Wrong Path Benchmark
30
+ ## Hallucination Leaderboard
57
31
 
58
- Generic agents often guess deployment tooling from the prompt alone:
32
+ Offline deterministic benchmark:
59
33
 
60
- ```text
61
- Prompt: Fix deployment
62
- Raw agent guess: Vercel, Docker, Railway
63
- ```
64
-
65
- ContextOS checks the repo first:
66
-
67
- ```text
68
- Detected evidence:
69
- - eas.json
70
- - expo dependency
71
- - GitHub workflow
72
-
73
- Selected skills:
74
- - eas
75
- - mobile-deployment
76
- - github-actions-ci-cd
77
- ```
78
-
79
- That is the core launch demo: same prompt, same model, different repo, correct next step.
80
-
81
- Internal fixture benchmark:
82
-
83
- | Metric | Result |
34
+ | System | Correct context choice |
84
35
  | --- | ---: |
85
- | Cases | 52 |
86
- | Top-1 Accuracy | 94.2% |
87
- | Top-3 Recall | 94.2% |
88
- | False Positive Rate | 0.0% |
89
- | Confidence Calibration | 100.0% |
90
- | Negative Gate Accuracy | 100.0% |
91
-
92
- This is an internal fixture benchmark, not an external real-world benchmark. It is designed to prove that ContextOS changes its suggestions from repo evidence across controlled Expo/EAS, Next/Vercel, Docker, Railway/Render, Firebase, auth, database, testing, mobile, and adversarial negative cases.
93
-
94
- Offline hallucination leaderboard:
36
+ | Raw heuristic baseline | 10.0% |
37
+ | ContextOS evidence benchmark | 80.0% |
95
38
 
96
39
  ```bash
97
40
  ctx leaderboard --hallucination
98
41
  ```
99
42
 
100
- Current deterministic result across 20 fixture tasks and 12 repo contexts:
101
-
102
- | System | Correct context choice |
103
- | --- | ---: |
104
- | Raw heuristic baseline | 10.0% |
105
- | ContextOS evidence benchmark | 80.0% |
106
-
107
43
  This means ContextOS improves deterministic context routing from 10% to 80% on the offline hallucination task set. It does not claim ContextOS beats Codex, Gemini, Claude Code, or Cursor in live runs.
108
44
 
109
45
  Live agent benchmark support exists, but results are pending an external environment with working CLI auth/session access:
@@ -122,7 +58,36 @@ Live benchmark tracking:
122
58
  - [Run Gemini CLI live benchmark](https://github.com/khovan123/contextOS/issues/4)
123
59
  - [Run Cursor live benchmark](https://github.com/khovan123/contextOS/issues/2)
124
60
 
125
- Example hook context injected before the agent works:
61
+ ## Why People Star ContextOS
62
+
63
+ - Agents ignore `AGENTS.md`.
64
+ - Agents choose the wrong deployment path.
65
+ - Agents grep random files before understanding the repo.
66
+ - ContextOS fixes all three before coding starts.
67
+
68
+ ## Demo
69
+
70
+ ![ContextOS demo: same prompt, different repo, correct skills](docs/demo/same-prompt-different-context.gif)
71
+
72
+ ```bash
73
+ ctx skills doctor -- "fix deployed"
74
+ ```
75
+
76
+ | Repo evidence | What ContextOS tells the agent |
77
+ | --- | --- |
78
+ | `eas.json`, `expo`, `react-native` | `eas`, `mobile-deployment`, `github-actions-ci-cd` |
79
+ | `vercel.json`, `next`, GitHub workflow | `vercel-deployment`, `github-actions-ci-cd`, `env-secret-management` |
80
+ | ContextOS repo with no app deploy evidence | no deployment skill selected |
81
+
82
+ More 10-second demo:
83
+
84
+ | Demo | GIF |
85
+ | --- | --- |
86
+ | AGENTS.md Lost In The Middle | [docs/demo/agents-lost-middle.gif](docs/demo/agents-lost-middle.gif) |
87
+
88
+ ## What The Agent Sees
89
+
90
+ ContextOS injects a compact brief before the agent works:
126
91
 
127
92
  ```text
128
93
  ## Critical ContextOS rules
@@ -148,6 +113,27 @@ Rule outcomes: 8 followed, 0 ignored, 0 unknown
148
113
  Runtime evidence: project graph was used before file search
149
114
  ```
150
115
 
116
+ Regenerate the GIFs from real local `ctx` command output:
117
+
118
+ ```bash
119
+ npm run demo:capture
120
+ ```
121
+
122
+ ## Internal Benchmark
123
+
124
+ Skill selection fixture benchmark:
125
+
126
+ | Metric | Result |
127
+ | --- | ---: |
128
+ | Cases | 52 |
129
+ | Top-1 Accuracy | 94.2% |
130
+ | Top-3 Recall | 94.2% |
131
+ | False Positive Rate | 0.0% |
132
+ | Confidence Calibration | 100.0% |
133
+ | Negative Gate Accuracy | 100.0% |
134
+
135
+ This is an internal fixture benchmark, not an external real-world benchmark. It is designed to prove that ContextOS changes its suggestions from repo evidence across controlled Expo/EAS, Next/Vercel, Docker, Railway/Render, Firebase, auth, database, testing, mobile, and adversarial negative cases.
136
+
151
137
  ## Quick Install
152
138
 
153
139
  Install in 30 seconds:
@@ -164,6 +150,13 @@ Scriptable setup:
164
150
  ```bash
165
151
  ctx setup --yes
166
152
  ctx setup --yes --agents codex,claude,agy
153
+ ctx setup --yes --generate-project-context
154
+ ```
155
+
156
+ If `ctx doctor` reports missing project skills/workflows, generate starter project context explicitly:
157
+
158
+ ```bash
159
+ ctx doctor --fix
167
160
  ```
168
161
 
169
162
  No global install:
@@ -188,27 +181,6 @@ ctx install agy
188
181
 
189
182
  Restart the agent after setup. Then use the agent normally.
190
183
 
191
- ## Why ContextOS Exists
192
-
193
- Developers put real operating instructions in `AGENTS.md`: use this graph tool before reading files, run these tests, follow this architecture boundary, avoid this migration path.
194
-
195
- The problem is not that agents cannot read `AGENTS.md`. The problem is that large context windows bury the important rule in the middle, where attention is weak.
196
-
197
- The same thing happens with project structure:
198
-
199
- - A deployment prompt says "fix deploy", and the agent guesses Vercel in an Expo repo.
200
- - A backend error mentions Fastify, and the agent loads frontend skills.
201
- - A feature request names one route, and the agent starts with broad grep instead of the files that matter.
202
-
203
- ContextOS fixes those three failures before the agent starts work.
204
-
205
- The next visible demo is not another feature. It is showing the pain in a few seconds:
206
-
207
- ```text
208
- Raw agent: guesses from the prompt.
209
- ContextOS: checks repo evidence first.
210
- ```
211
-
212
184
  ## What ContextOS Does
213
185
 
214
186
  | Agent failure | ContextOS behavior |
@@ -290,6 +262,7 @@ The score checks project `AGENTS.md` rules, project skill packs under `.codex/sk
290
262
  | `ctx setup` | Recommended first-run install flow. |
291
263
  | `ctx debug -- "Recheck authen flow"` | Preview what ContextOS would inject. |
292
264
  | `ctx doctor` | Score repository readiness for the `ContextOS Ready` badge. |
265
+ | `ctx doctor --fix` | Generate starter project skills and workflow when the repo is missing them. |
293
266
  | `ctx report` | Show the last task's compliance summary. |
294
267
  | `ctx evidence` | Show why each rule was marked followed/ignored/unknown. |
295
268
  | `ctx stats` | Show workspace-level usage and effectiveness metrics. |
@@ -611,12 +584,14 @@ This warning comes from a transitive dependency in the local embedding/WASM stac
611
584
  | `ctx install --copy` | Copies only the plugin payload to `$CODEX_HOME/plugins/ctx`. | Legacy local development or manual plugin experiments. | Does not sync the active marketplace, rebuild indexes, register MCP, or install global hooks. Prefer `ctx refresh` for active local updates. |
612
585
  | `ctx setup` | Runs the first-run setup wizard. | You want the recommended onboarding flow after `npm install -g @minhpnq1807/contextos`. | Installs selected agents, optionally syncs Ruler rules/MCP and skillshare skills, asks which prompt sections to show, then prints next steps. |
613
586
  | `ctx setup --yes` | Runs setup with defaults non-interactively. | You want scriptable Codex setup. | Uses `codex`, enables injection, syncs rules, syncs skills, skips interactive community-skill installation when no TTY is available, and passes `--yes` to dependency setup prompts. Use `--agents codex,claude,agy` for multi-agent setup. |
587
+ | `ctx setup --generate-project-context` | Generates starter project skills and workflow during setup. | Your repo has rules but `ctx doctor` reports missing skills/workflows. | Creates `.codex/skills/<detected-skill>/SKILL.md`, matching `skill.yaml`, and `.codex/workflows/primary.md` without overwriting existing files. |
614
588
  | `ctx setup --agents <list>` | Runs setup for selected agents. | You want only part of the default set. | Accepts comma-separated `codex`, `claude`, `agy`, or `antigravity`. |
615
589
  | `ctx setup --no-rules` | Skips Ruler sync during setup. | You only want hooks/MCP install and maybe skill sync. | Does not run `ctx sync --rules`. |
616
590
  | `ctx setup --no-skills` | Skips skillshare sync during setup. | You do not want shared skills configured. | Does not run `ctx sync --skills`. |
617
591
  | `ctx setup --quiet` | Runs setup in measurement-only mode. | You want reports/stats without visible injected prompt context. | Installs hooks with prompt context injection disabled. |
618
592
  | `ctx debug -- "task"` | Runs the scheduler locally for a fake prompt. | You want to see which AGENTS.md rules and files ContextOS would inject before using Codex. | Prints rule scores, scoring reasons, suggested files, and final `additionalContext`. |
619
593
  | `ctx doctor` | Scores repository ContextOS readiness. | You want to add or verify a `ContextOS Ready` badge. | Prints Rules, Skills, Workflows, Overall tier, evidence, and next recommendations. |
594
+ | `ctx doctor --fix` | Generates starter ContextOS project context. | `ctx doctor` says skills/workflows are missing and you want explicit local scaffolding. | Detects package/config evidence, creates up to three starter project skills plus `.codex/workflows/primary.md`, then prints the updated readiness score. |
620
595
  | `ctx report` | Shows the last Stop-hook compliance report for the current workspace. | An agent task has finished and you want the summary again. | Prints sectioned tables for summary, rule outcomes, suggested files, and runtime telemetry from `~/.ctx/contextos/workspaces/<workspace-id>/last-report.json`. |
621
596
  | `ctx evidence` | Shows detailed evidence behind the last report for the current workspace. | You want to inspect why a rule was marked `followed`, `ignored`, `unknown`, or `unmeasurable`. | Prints a compact evidence table plus per-rule detail tables. |
622
597
  | `ctx stats` | Shows aggregate runtime metrics for the current workspace. | You want to know whether ContextOS is active and useful over time. | Prints sectioned tables for prompt/report counts, injection rate, efficiency, rule outcomes, hook events, last prompt, and last report. |
package/bin/ctx.js CHANGED
@@ -44,6 +44,7 @@ import { fetchSkillsForAgents, printSkillRecommendations, getAllLibraries, getIn
44
44
  import { invalidateCtxMcpSocket } from "../plugins/ctx/lib/ctx-mcp-client.js";
45
45
  import { runPrefixedCommand } from "../plugins/ctx/lib/shell-runner.js";
46
46
  import { formatContextOSReady, inspectContextOSReady } from "../plugins/ctx/lib/certification.js";
47
+ import { formatProjectContextGeneration, generateProjectContext } from "../plugins/ctx/lib/project-context-generator.js";
47
48
 
48
49
  /**
49
50
  * Run a shell command with all output lines prefixed by │
@@ -189,11 +190,14 @@ Usage:
189
190
  ctx setup Interactive full setup wizard
190
191
  ctx setup --yes Auto-confirm all setup prompts
191
192
  ctx setup --agents <names> Pre-select agents to install
193
+ ctx setup --generate-project-context Generate starter project skills/workflow
192
194
  ctx setup --no-rules Skip AGENTS.md rule sync
193
195
  ctx setup --no-skills Skip skill sync
194
196
  ctx setup --quiet Quiet mode (minimal output)
195
197
  ctx debug -- "task" Debug a task with ContextOS tracing
196
198
  ctx doctor Score repository ContextOS readiness
199
+ ctx doctor --fix Generate starter project skills/workflow
200
+ ctx doctor --fix --force Regenerate starter project context files
197
201
  ctx report Show last ContextOS compliance report
198
202
  ctx evidence Show evidence from last report
199
203
  ctx stats Show workspace statistics
@@ -880,6 +884,22 @@ async function setup({ args = [], cwd = process.cwd() } = {}) {
880
884
  });
881
885
  }
882
886
 
887
+ if (interactive && !options.generateProjectContext) {
888
+ const readiness = inspectContextOSReady({ cwd });
889
+ if (readiness.skills.score < 50 || readiness.workflows.score < 50) {
890
+ const rl = readline.createInterface({ input, output });
891
+ try {
892
+ options.generateProjectContext = await askSetupYesNo(
893
+ rl,
894
+ "Generate starter project skills and workflow?",
895
+ true
896
+ );
897
+ } finally {
898
+ rl.close();
899
+ }
900
+ }
901
+ }
902
+
883
903
  console.log("");
884
904
  console.log("◇ Ready to setup:");
885
905
  for (const line of setupSummaryLines({
@@ -892,6 +912,13 @@ async function setup({ args = [], cwd = process.cwd() } = {}) {
892
912
 
893
913
  if (!options.agents.length) throw new Error("No agents selected. Use --agents codex,claude,antigravity,copilot.");
894
914
 
915
+ if (options.generateProjectContext) {
916
+ console.log("◇ Generating starter project context...");
917
+ const generated = generateProjectContext({ cwd });
918
+ for (const line of formatProjectContextGeneration(generated).split("\n")) console.log(`│ ${line}`);
919
+ console.log("");
920
+ }
921
+
895
922
  for (const agent of options.agents) {
896
923
  console.log(`◇ Setting up ${agent}...`);
897
924
  await streamSetupOutput(() => install({ agent, copy: false }));
@@ -1022,7 +1049,14 @@ try {
1022
1049
  if (!task.trim()) throw new Error('Usage: ctx debug -- "task"');
1023
1050
  await debug(task);
1024
1051
  } else if (command === "doctor") {
1025
- console.log(formatContextOSReady(inspectContextOSReady({ cwd: process.cwd() })));
1052
+ if (args.includes("--fix")) {
1053
+ const generated = generateProjectContext({ cwd: process.cwd(), force: args.includes("--force") });
1054
+ console.log(formatProjectContextGeneration(generated));
1055
+ console.log("");
1056
+ console.log(formatContextOSReady(inspectContextOSReady({ cwd: process.cwd() })));
1057
+ } else {
1058
+ console.log(formatContextOSReady(inspectContextOSReady({ cwd: process.cwd() })));
1059
+ }
1026
1060
  } else if (command === "refresh") {
1027
1061
  await refresh();
1028
1062
  } else if (command === "autowarm") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minhpnq1807/contextos",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Task-aware AGENTS.md context injection and compliance reporting for Codex, Claude Code, and Antigravity.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctx",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Inject task-relevant AGENTS.md rules into Codex through plugin hooks.",
5
5
  "author": {
6
6
  "name": "ContextOS"
@@ -68,6 +68,9 @@ export function formatContextOSReady(result) {
68
68
  if (next.length) {
69
69
  lines.push("", "Next:");
70
70
  for (const item of [...new Set(next)].slice(0, 5)) lines.push(`- ${item}`);
71
+ if (result.skills.score < 50 || result.workflows.score < 50) {
72
+ lines.push("- Run `ctx doctor --fix` to generate starter project skills and workflow.");
73
+ }
71
74
  }
72
75
 
73
76
  return lines.join("\n");
@@ -0,0 +1,389 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { clearSkillScanCache } from "./skill-discoverer.js";
5
+
6
+ const STARTER_SKILL_LIMIT = 3;
7
+
8
+ export function generateProjectContext({ cwd = process.cwd(), force = false } = {}) {
9
+ const root = findProjectRoot(cwd);
10
+ const profile = detectProjectProfile(root);
11
+ const skills = selectStarterSkills(profile).slice(0, STARTER_SKILL_LIMIT);
12
+ const created = [];
13
+ const skipped = [];
14
+
15
+ for (const skill of skills) {
16
+ const dir = path.join(root, ".codex", "skills", skill.id);
17
+ const skillPath = path.join(dir, "SKILL.md");
18
+ const yamlPath = path.join(dir, "skill.yaml");
19
+ fs.mkdirSync(dir, { recursive: true });
20
+ writeFile({ filePath: skillPath, content: renderSkillMarkdown(skill), force, created, skipped });
21
+ writeFile({ filePath: yamlPath, content: renderSkillYaml(skill), force, created, skipped });
22
+ }
23
+
24
+ const workflowPath = path.join(root, ".codex", "workflows", "primary.md");
25
+ fs.mkdirSync(path.dirname(workflowPath), { recursive: true });
26
+ writeFile({
27
+ filePath: workflowPath,
28
+ content: renderPrimaryWorkflow(profile, skills),
29
+ force,
30
+ created,
31
+ skipped
32
+ });
33
+ clearSkillScanCache();
34
+
35
+ return {
36
+ root,
37
+ profile,
38
+ skills: skills.map((skill) => skill.id),
39
+ created,
40
+ skipped
41
+ };
42
+ }
43
+
44
+ export function formatProjectContextGeneration(result) {
45
+ const lines = [
46
+ "Project context generated",
47
+ "",
48
+ `Root: ${result.root}`,
49
+ `Detected: ${result.profile.summary}`,
50
+ `Skills: ${result.skills.join(", ") || "(none)"}`,
51
+ "",
52
+ "Created:"
53
+ ];
54
+ if (result.created.length) {
55
+ for (const filePath of result.created) lines.push(`- ${path.relative(result.root, filePath)}`);
56
+ } else {
57
+ lines.push("- none");
58
+ }
59
+ if (result.skipped.length) {
60
+ lines.push("", "Skipped existing files:");
61
+ for (const filePath of result.skipped) lines.push(`- ${path.relative(result.root, filePath)}`);
62
+ }
63
+ lines.push("", "Next:");
64
+ lines.push("- Review generated skills/workflow and edit project-specific wording.");
65
+ lines.push("- Run: ctx doctor");
66
+ lines.push("- Run: ctx debug -- \"your task\"");
67
+ return lines.join("\n");
68
+ }
69
+
70
+ function detectProjectProfile(root) {
71
+ const packageFiles = findPackageJsonFiles(root);
72
+ const packages = packageFiles.map((filePath) => ({
73
+ filePath,
74
+ json: safeJson(filePath)
75
+ })).filter((item) => item.json);
76
+ const dependencies = new Set();
77
+ const scripts = new Set();
78
+ for (const item of packages) {
79
+ for (const section of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
80
+ for (const name of Object.keys(item.json[section] || {})) dependencies.add(name);
81
+ }
82
+ for (const name of Object.keys(item.json.scripts || {})) scripts.add(name);
83
+ }
84
+ const files = new Set([
85
+ ...findExisting(root, [
86
+ "eas.json",
87
+ "app.json",
88
+ "app.config.js",
89
+ "app.config.ts",
90
+ "vercel.json",
91
+ "Dockerfile",
92
+ "docker-compose.yml",
93
+ "compose.yml",
94
+ "railway.json",
95
+ "render.yaml",
96
+ "firebase.json",
97
+ "prisma/schema.prisma",
98
+ "jest.config.js",
99
+ "jest.config.ts",
100
+ "playwright.config.ts",
101
+ ".github/workflows"
102
+ ])
103
+ ]);
104
+
105
+ const has = (name) => dependencies.has(name);
106
+ const hasFile = (name) => files.has(name);
107
+ const platforms = [];
108
+ if (has("expo") || has("react-native") || hasFile("eas.json")) platforms.push("expo-mobile");
109
+ if (has("next") || hasFile("vercel.json")) platforms.push("next-web");
110
+ if (has("@nestjs/core")) platforms.push("nestjs-backend");
111
+ if (has("express")) platforms.push("express-backend");
112
+ if (has("prisma") || has("@prisma/client") || hasFile("prisma/schema.prisma")) platforms.push("prisma");
113
+ if (has("redis") || has("ioredis")) platforms.push("redis");
114
+ if (hasFile("Dockerfile") || hasFile("docker-compose.yml")) platforms.push("docker");
115
+ if (hasFile(".github/workflows")) platforms.push("github-actions");
116
+ if (has("jest") || has("vitest") || hasFile("jest.config.js") || hasFile("playwright.config.ts")) platforms.push("testing");
117
+
118
+ const summary = platforms.length
119
+ ? platforms.join(", ")
120
+ : packages.length
121
+ ? `${packages.length} package.json file(s)`
122
+ : "generic repository";
123
+
124
+ return {
125
+ root,
126
+ packageFiles,
127
+ dependencies,
128
+ scripts,
129
+ files,
130
+ platforms,
131
+ summary
132
+ };
133
+ }
134
+
135
+ function selectStarterSkills(profile) {
136
+ const skills = [];
137
+ const hasPlatform = (platform) => profile.platforms.includes(platform);
138
+ if (hasPlatform("expo-mobile")) {
139
+ skills.push(skill({
140
+ id: "mobile-deployment",
141
+ name: "Mobile Deployment",
142
+ description: "Use for Expo, React Native, EAS build, QR/dev-client, Android/iOS preview, and mobile release tasks.",
143
+ prompts: ["expo", "react native", "eas", "mobile", "qr", "android", "ios", "preview", "production", "deploy"],
144
+ files: ["eas.json", "app.json", "app.config.ts", ".github/workflows/*"],
145
+ dependencies: ["expo", "react-native", "eas-cli"],
146
+ negatives: ["vercel", "serverless web deployment"]
147
+ }));
148
+ }
149
+ if (hasPlatform("next-web")) {
150
+ skills.push(skill({
151
+ id: "nextjs-web",
152
+ name: "Next.js Web",
153
+ description: "Use for Next.js routes, App Router, server/client component boundaries, Vercel deploys, and web UI tasks.",
154
+ prompts: ["next", "nextjs", "app router", "route", "page", "component", "vercel", "webapp"],
155
+ files: ["app/**", "pages/**", "next.config.*", "vercel.json"],
156
+ dependencies: ["next", "react"],
157
+ negatives: ["expo", "eas", "android", "ios"]
158
+ }));
159
+ }
160
+ if (hasPlatform("nestjs-backend") || hasPlatform("express-backend")) {
161
+ skills.push(skill({
162
+ id: "backend-api",
163
+ name: "Backend API",
164
+ description: "Use for backend services, API endpoints, validation, auth, controllers/routes, and service-layer changes.",
165
+ prompts: ["api", "backend", "service", "controller", "route", "auth", "validation", "fastify", "express", "nestjs"],
166
+ files: ["services/**", "src/**", "apps/**", "libs/**"],
167
+ dependencies: ["@nestjs/core", "express", "fastify", "zod", "class-validator"],
168
+ negatives: ["pure css", "static copy"]
169
+ }));
170
+ }
171
+ if (hasPlatform("prisma")) {
172
+ skills.push(skill({
173
+ id: "database-prisma",
174
+ name: "Database Prisma",
175
+ description: "Use for Prisma schema, migrations, query performance, repositories, and database-backed tests.",
176
+ prompts: ["prisma", "database", "migration", "query", "schema", "seed", "transaction"],
177
+ files: ["prisma/schema.prisma", "prisma/**", "src/**/repository*", "services/**/repository*"],
178
+ dependencies: ["prisma", "@prisma/client"],
179
+ negatives: ["frontend-only", "css-only"]
180
+ }));
181
+ }
182
+ if (hasPlatform("redis")) {
183
+ skills.push(skill({
184
+ id: "redis-cache",
185
+ name: "Redis Cache",
186
+ description: "Use for cache, queues, sessions, rate limits, Redis clients, and invalidation behavior.",
187
+ prompts: ["redis", "cache", "queue", "session", "rate limit", "invalidation"],
188
+ files: ["src/**/cache*", "services/**/cache*", "libs/**/cache*"],
189
+ dependencies: ["redis", "ioredis", "bullmq"],
190
+ negatives: ["static page"]
191
+ }));
192
+ }
193
+ if (hasPlatform("docker") || hasPlatform("github-actions")) {
194
+ skills.push(skill({
195
+ id: "ci-deployment",
196
+ name: "CI Deployment",
197
+ description: "Use for Docker, GitHub Actions, build logs, deploy failures, environment variables, and release pipelines.",
198
+ prompts: ["ci", "github actions", "docker", "deploy", "build failed", "pipeline", "environment", "secret"],
199
+ files: [".github/workflows/*", "Dockerfile", "docker-compose.yml", "railway.json", "render.yaml"],
200
+ dependencies: [],
201
+ negatives: ["local ui styling only"]
202
+ }));
203
+ }
204
+ if (hasPlatform("testing")) {
205
+ skills.push(skill({
206
+ id: "project-testing",
207
+ name: "Project Testing",
208
+ description: "Use for unit, integration, e2e, Jest, Vitest, Playwright, and focused verification tasks.",
209
+ prompts: ["test", "jest", "vitest", "playwright", "e2e", "coverage", "failing test"],
210
+ files: ["test/**", "__tests__/**", "*.spec.*", "*.test.*", "playwright.config.ts"],
211
+ dependencies: ["jest", "vitest", "@playwright/test"],
212
+ negatives: ["docs-only"]
213
+ }));
214
+ }
215
+ while (skills.length < STARTER_SKILL_LIMIT) {
216
+ const fallback = [
217
+ skill({
218
+ id: "project-implementation",
219
+ name: "Project Implementation",
220
+ description: "Use for normal feature work, bug fixes, and scoped implementation tasks in this repository.",
221
+ prompts: ["implement", "fix", "add", "update", "refactor", "bug"],
222
+ files: ["src/**", "apps/**", "services/**", "libs/**"],
223
+ dependencies: [],
224
+ negatives: ["release notes only"]
225
+ }),
226
+ skill({
227
+ id: "project-debugging",
228
+ name: "Project Debugging",
229
+ description: "Use for runtime errors, failed commands, logs, CI failures, and root-cause analysis.",
230
+ prompts: ["error", "failed", "timeout", "debug", "logs", "cannot", "fix"],
231
+ files: ["package.json", ".github/workflows/*", "src/**", "services/**"],
232
+ dependencies: [],
233
+ negatives: ["new feature with no failure"]
234
+ }),
235
+ skill({
236
+ id: "project-documentation",
237
+ name: "Project Documentation",
238
+ description: "Use for README, changelog, architecture notes, specs, and project documentation updates.",
239
+ prompts: ["readme", "docs", "documentation", "changelog", "spec", "guide"],
240
+ files: ["README.md", "docs/**", "CHANGELOG.md", "AGENTS.md"],
241
+ dependencies: [],
242
+ negatives: ["runtime bug"]
243
+ })
244
+ ].find((item) => !skills.some((existing) => existing.id === item.id));
245
+ if (!fallback) break;
246
+ skills.push(fallback);
247
+ }
248
+ return dedupeById(skills);
249
+ }
250
+
251
+ function skill({ id, name, description, prompts, files, dependencies, negatives }) {
252
+ return { id, name, description, prompts, files, dependencies, negatives };
253
+ }
254
+
255
+ function renderSkillMarkdown(skill) {
256
+ return [
257
+ `# ${skill.name}`,
258
+ "",
259
+ skill.description,
260
+ "",
261
+ "Use this skill when the prompt and project evidence match the metadata in `skill.yaml`.",
262
+ "",
263
+ "Before editing:",
264
+ "",
265
+ "1. Read the relevant project rules.",
266
+ "2. Inspect the suggested files and nearby tests.",
267
+ "3. Keep the change scoped to the task.",
268
+ "4. Run the focused verification command before final response.",
269
+ ""
270
+ ].join("\n");
271
+ }
272
+
273
+ function renderSkillYaml(skill) {
274
+ return [
275
+ `id: ${skill.id}`,
276
+ `name: ${skill.name}`,
277
+ `description: ${skill.description}`,
278
+ "positive_triggers:",
279
+ " prompts:",
280
+ ...skill.prompts.map((item) => ` - ${quoteYaml(item)}`),
281
+ " files:",
282
+ ...skill.files.map((item) => ` - ${quoteYaml(item)}`),
283
+ " dependencies:",
284
+ ...(skill.dependencies.length ? skill.dependencies.map((item) => ` - ${quoteYaml(item)}`) : [" - package.json"]),
285
+ "evidence:",
286
+ " files:",
287
+ ...skill.files.slice(0, 4).map((item) => ` - ${quoteYaml(item)}`),
288
+ " dependencies:",
289
+ ...(skill.dependencies.length ? skill.dependencies.map((item) => ` - ${quoteYaml(item)}`) : [" - package.json"]),
290
+ "negative_triggers:",
291
+ " prompts:",
292
+ ...skill.negatives.map((item) => ` - ${quoteYaml(item)}`),
293
+ "workflow:",
294
+ " - Inspect repo evidence before choosing an implementation path.",
295
+ " - Read the suggested files and nearest tests.",
296
+ " - Implement the smallest scoped change.",
297
+ " - Run focused verification and summarize evidence.",
298
+ ""
299
+ ].join("\n");
300
+ }
301
+
302
+ function renderPrimaryWorkflow(profile, skills) {
303
+ return [
304
+ "# Primary Workflow",
305
+ "",
306
+ `Use this workflow for common tasks in this repository. Detected project context: ${profile.summary}.`,
307
+ "",
308
+ "planner -> tester -> code-reviewer -> docs-manager",
309
+ "",
310
+ "1. Read the task and relevant AGENTS.md rules.",
311
+ "2. Check ContextOS suggested files and skills.",
312
+ "3. Inspect project config before choosing a deployment/framework path.",
313
+ "4. Implement the smallest scoped change.",
314
+ "5. Run focused tests or the closest available verification.",
315
+ "6. Summarize files changed, verification, and any remaining risk.",
316
+ "",
317
+ "Starter skills:",
318
+ ...skills.map((skill) => `- ${skill.id}: ${skill.description}`),
319
+ ""
320
+ ].join("\n");
321
+ }
322
+
323
+ function writeFile({ filePath, content, force, created, skipped }) {
324
+ if (fs.existsSync(filePath) && !force) {
325
+ skipped.push(filePath);
326
+ return;
327
+ }
328
+ fs.writeFileSync(filePath, content, "utf8");
329
+ created.push(filePath);
330
+ }
331
+
332
+ function findPackageJsonFiles(root) {
333
+ const files = [];
334
+ walk(root, files, (filePath) => path.basename(filePath) === "package.json", 0);
335
+ return files.slice(0, 20);
336
+ }
337
+
338
+ function findExisting(root, relativePaths) {
339
+ return relativePaths.filter((relativePath) => fs.existsSync(path.join(root, relativePath)));
340
+ }
341
+
342
+ function walk(directory, files, predicate, depth) {
343
+ if (depth > 4) return;
344
+ let entries = [];
345
+ try {
346
+ entries = fs.readdirSync(directory, { withFileTypes: true });
347
+ } catch {
348
+ return;
349
+ }
350
+ for (const entry of entries) {
351
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".ctx") continue;
352
+ const filePath = path.join(directory, entry.name);
353
+ if (entry.isDirectory()) walk(filePath, files, predicate, depth + 1);
354
+ else if (entry.isFile() && predicate(filePath)) files.push(filePath);
355
+ }
356
+ }
357
+
358
+ function safeJson(filePath) {
359
+ try {
360
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
361
+ } catch {
362
+ return null;
363
+ }
364
+ }
365
+
366
+ function findProjectRoot(cwd) {
367
+ let current = path.resolve(cwd);
368
+ while (true) {
369
+ if (fs.existsSync(path.join(current, ".git"))) return current;
370
+ const parent = path.dirname(current);
371
+ if (parent === current) return path.resolve(cwd);
372
+ current = parent;
373
+ }
374
+ }
375
+
376
+ function dedupeById(skills) {
377
+ const seen = new Set();
378
+ const result = [];
379
+ for (const skill of skills) {
380
+ if (seen.has(skill.id)) continue;
381
+ seen.add(skill.id);
382
+ result.push(skill);
383
+ }
384
+ return result;
385
+ }
386
+
387
+ function quoteYaml(value) {
388
+ return JSON.stringify(String(value));
389
+ }
@@ -19,7 +19,8 @@ export function parseSetupArgs(args = []) {
19
19
  yes,
20
20
  quiet: args.includes("--quiet"),
21
21
  syncRules: !args.includes("--no-rules"),
22
- syncSkills: !args.includes("--no-skills")
22
+ syncSkills: !args.includes("--no-skills"),
23
+ generateProjectContext: args.includes("--generate-project-context")
23
24
  };
24
25
  }
25
26
 
@@ -42,6 +43,7 @@ export function setupSummaryLines({
42
43
  agents = DEFAULT_AGENTS,
43
44
  syncRules = true,
44
45
  syncSkills = true,
46
+ generateProjectContext = false,
45
47
  promptSections = null,
46
48
  promptLimits = null
47
49
  } = {}) {
@@ -50,7 +52,8 @@ export function setupSummaryLines({
50
52
  `Agents: ${agents.join(", ") || "(none)"}`,
51
53
  `Prompt context injection: always enabled`,
52
54
  `Ruler rule/MCP sync: ${syncRules ? "enabled" : "skipped"}`,
53
- `skillshare skill sync: ${syncSkills ? "enabled" : "skipped"}`
55
+ `skillshare skill sync: ${syncSkills ? "enabled" : "skipped"}`,
56
+ `Project context generation: ${generateProjectContext ? "enabled" : "skipped"}`
54
57
  ];
55
58
  if (promptSections !== null) lines.push(`Prompt sections shown: ${promptSections}`);
56
59
  if (promptLimits !== null) lines.push(`Prompt suggest limits: ${promptLimits}`);
@@ -20,6 +20,10 @@ const DEFAULT_ROUTER_THRESHOLD = 0.35;
20
20
 
21
21
  const scanCache = new Map();
22
22
 
23
+ export function clearSkillScanCache() {
24
+ scanCache.clear();
25
+ }
26
+
23
27
  export function skillSearchRoots({ cwd = process.cwd(), home = os.homedir() } = {}) {
24
28
  return [
25
29
  path.join(cwd, ".codex", "skills"),