@esoteric-logic/praxis-harness 2.14.0 → 2.15.0

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 (39) hide show
  1. package/base/skills/px-prompt/SKILL.md +373 -0
  2. package/bin/praxis.js +7 -0
  3. package/bin/prompt-blocks.js +145 -0
  4. package/bin/prompt-compile.js +313 -0
  5. package/lib/assemblers.js +249 -0
  6. package/lib/loader.js +148 -0
  7. package/package.json +10 -3
  8. package/prompts/blocks/behaviors/flag-confidence.md +13 -0
  9. package/prompts/blocks/behaviors/handle-uncertainty.md +13 -0
  10. package/prompts/blocks/behaviors/no-flattery.md +15 -0
  11. package/prompts/blocks/behaviors/recommend-with-reasons.md +13 -0
  12. package/prompts/blocks/behaviors/verify-before-reporting.md +13 -0
  13. package/prompts/blocks/context/mcp-servers.md +12 -0
  14. package/prompts/blocks/context/official-docs-first.md +16 -0
  15. package/prompts/blocks/context/praxis-workflow.md +20 -0
  16. package/prompts/blocks/context/vault-integration.md +13 -0
  17. package/prompts/blocks/domains/cloud-infrastructure.md +13 -0
  18. package/prompts/blocks/domains/govcon.md +13 -0
  19. package/prompts/blocks/domains/web-development.md +13 -0
  20. package/prompts/blocks/formats/concise-responses.md +13 -0
  21. package/prompts/blocks/formats/what-so-what-now-what.md +16 -0
  22. package/prompts/blocks/identity/research-partner.md +10 -0
  23. package/prompts/blocks/identity/senior-engineer.md +15 -0
  24. package/prompts/blocks/identity/solutions-architect.md +13 -0
  25. package/prompts/profiles/_base.yaml +15 -0
  26. package/prompts/profiles/federal-cloud.yaml +18 -0
  27. package/prompts/profiles/praxis.yaml +13 -0
  28. package/prompts/projects/_template/prompt-config.yaml +34 -0
  29. package/prompts/projects/maximus/prompt-config.yaml +13 -0
  30. package/prompts/projects/maximus/references/maturity-questions.md +634 -0
  31. package/prompts/projects/maximus/references/phase-maturity-matrix.md +188 -0
  32. package/prompts/projects/maximus/references/proposal-writing-standards.md +367 -0
  33. package/prompts/projects/maximus/space-instructions.md +67 -0
  34. package/prompts/projects/maximus/system-prompt.md +641 -0
  35. package/prompts/projects/praxis/CLAUDE.md +84 -0
  36. package/prompts/projects/praxis/project-instructions.md +24 -0
  37. package/prompts/projects/praxis/prompt-config.yaml +40 -0
  38. package/prompts/projects/praxis/space-instructions.md +28 -0
  39. package/scripts/lint-harness.sh +42 -0
@@ -0,0 +1,373 @@
1
+ ---
2
+ name: px-prompt
3
+ disable-model-invocation: true
4
+ description: "Unified prompt engine. Creates, generates, condenses, and syncs system prompts for Claude Projects, Perplexity Spaces, and Claude Code. Auto-detects what to do based on project state."
5
+ ---
6
+
7
+ # px-prompt Skill
8
+
9
+ ## Overview
10
+ Single entry point for the prompt engine. Detects what needs to happen based on project state and user intent.
11
+
12
+ ## Invocation
13
+ - `/px-prompt <project-name>` — create, generate, or regenerate a project's prompts
14
+ - `/px-prompt --sync` — recompile all projects, report diffs and budgets
15
+ - `/px-prompt --list` — list all projects and their status
16
+
17
+ ---
18
+
19
+ ## Routing Logic
20
+
21
+ When invoked with a project name, detect the right action:
22
+
23
+ ```
24
+ /px-prompt <project-name>
25
+
26
+ ├─ Project doesn't exist?
27
+ │ → ACTION: CREATE (Step 1)
28
+
29
+ ├─ Project exists, mode: standalone, system-prompt.md missing?
30
+ │ → ACTION: GENERATE FROM SCRATCH (Step 2)
31
+
32
+ ├─ Project exists, mode: standalone, system-prompt.md exists, platform outputs missing?
33
+ │ → ACTION: CONDENSE (Step 3)
34
+
35
+ ├─ Project exists, mode: standalone, all files present?
36
+ │ → ACTION: VALIDATE + offer to regenerate (Step 4)
37
+
38
+ ├─ Project exists, mode: compiled?
39
+ │ → ACTION: COMPILE (Step 4)
40
+
41
+ └─ --sync flag?
42
+ → ACTION: SYNC ALL (Step 5)
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Step 1 — CREATE: New project scaffold
48
+
49
+ **Triggered when:** project folder doesn't exist.
50
+
51
+ ### 1a. Core intake (always ask)
52
+
53
+ 1. **Description** — "Describe this project in one sentence."
54
+
55
+ 2. **Role** — "Who is the AI in this project?"
56
+ - Show available identity blocks: `node bin/prompt-blocks.js --category identity`
57
+ - User can pick one OR describe a custom role
58
+
59
+ 3. **Target platforms** — "Which platforms will you deploy to?"
60
+ - Multi-select: Claude Projects, Perplexity Spaces, Claude Code
61
+ - Default: Claude Projects + Perplexity Spaces
62
+
63
+ 4. **Complexity** — Based on the description, recommend a mode:
64
+ - Simple/standard project → **compiled** (block-based, continue to 1b)
65
+ - Complex multi-role agent → **standalone** with AI generation (continue to 1c)
66
+ - User already has a prompt → **standalone** paste-in (scaffold folder, skip to Step 3)
67
+
68
+ ### 1b. Compiled project setup
69
+
70
+ 5. **Domain expertise** — Show available domain blocks:
71
+ ```bash
72
+ node bin/prompt-blocks.js --category domains
73
+ ```
74
+ User picks from list or describes custom domains.
75
+ For custom domains: create a new block file at `prompts/blocks/domains/<id>.md`.
76
+
77
+ 6. **Research domains** (if Perplexity selected) — "What topics should Perplexity prioritize?"
78
+ Suggest based on selected domains. User accepts or customizes.
79
+
80
+ 7. **Knowledge files** — "Reference documents to upload alongside? (compliance matrices, standards, playbooks)"
81
+
82
+ 8. **Claude Code extras** (only if Claude Code selected) — tech stack, commands, git identity
83
+
84
+ 9. **Build project folder:**
85
+ ```bash
86
+ mkdir -p prompts/projects/<project-name>/references
87
+ ```
88
+
89
+ Write `prompt-config.yaml`:
90
+ ```yaml
91
+ project: <project-name>
92
+ description: <from intake>
93
+ mode: compiled
94
+ version: "1.0"
95
+ platforms: [claude-project, perplexity-space]
96
+ profile: null
97
+ blocks:
98
+ identity: [<matched-block>]
99
+ domains: [<selected-blocks>]
100
+ behaviors: []
101
+ formats: []
102
+ context: [<auto-selected by platform>]
103
+ research_domains: [<from intake>]
104
+ knowledge_files: [<from intake>]
105
+ ```
106
+
107
+ **Auto-add context blocks by platform:**
108
+ - Perplexity → `official-docs-first`, `flag-confidence`
109
+ - Claude Code → `vault-integration`, `mcp-servers`, `praxis-workflow`
110
+
111
+ 10. **Compile:** `node bin/prompt-compile.js <project-name>`
112
+
113
+ 11. → Go to **Step 4** (results + deployment)
114
+
115
+ ### 1c. Standalone project with AI generation
116
+
117
+ → Go to **Step 2** (generate from scratch)
118
+
119
+ ---
120
+
121
+ ## Step 2 — GENERATE: AI-powered system prompt creation
122
+
123
+ **Triggered when:** standalone project exists but `system-prompt.md` is empty/missing, OR user explicitly requests generation.
124
+
125
+ ### 2a. Intake (if not already gathered in Step 1)
126
+
127
+ 1. **Description** — 2-3 sentences about the project
128
+ 2. **Role** — primary AI responsibility
129
+ 3. **Domains** — expertise areas (free-form, not limited to existing blocks)
130
+ 4. **Key behaviors** — rules beyond defaults
131
+ 5. **Target audience** — who reads the output
132
+ 6. **Knowledge files** — reference documents
133
+ 7. **Target platforms** — deployment targets
134
+
135
+ ### 2b. Domain research via Perplexity
136
+
137
+ **Mandatory before generating.** For each domain, run Perplexity queries:
138
+
139
+ **Query 1 — Best practices:**
140
+ ```
141
+ perplexity_ask: "What are the current best practices for [domain]
142
+ AI assistants in 2025-2026? Key terminology, active standards,
143
+ common workflows, expert expectations."
144
+ ```
145
+
146
+ **Query 2 — Standards:**
147
+ ```
148
+ perplexity_search: "[domain] key frameworks standards certifications 2025"
149
+ ```
150
+
151
+ **Query 3 — Use cases:**
152
+ ```
153
+ perplexity_ask: "What are the most common tasks [target audience]
154
+ asks AI assistants to help with in [domain]? Top 10 use cases."
155
+ ```
156
+
157
+ If Perplexity unavailable: state "Domain research could not be completed — prompt uses training data only. Review for currency." and proceed.
158
+
159
+ ### 2c. Generate system-prompt.md
160
+
161
+ Using intake + Perplexity research, generate following the 5-layer skeleton:
162
+
163
+ ```markdown
164
+ ---
165
+ version: "1.0"
166
+ date: [today]
167
+ platform: claude-project
168
+ generated_by: px-prompt
169
+ ---
170
+
171
+ ## Role
172
+ [One-sentence role from intake, using current terminology from research]
173
+
174
+ ## Behavioral Constraints
175
+ [_base defaults: no-flattery, verify-before-reporting, recommend-with-reasons, handle-uncertainty]
176
+ [Custom behaviors from intake]
177
+ [Domain-specific constraints from research]
178
+
179
+ ## Domain Expertise
180
+ [Structured areas from research — current framework names, standard versions]
181
+
182
+ ## Output Format
183
+ [Format rules for target audience]
184
+ [What/So What/Now What for analytical outputs]
185
+
186
+ ## Common Tasks
187
+ [Top 5-10 use cases from Perplexity research]
188
+
189
+ ## Knowledge Interaction Rules
190
+ [How to use reference files, when to cite, quote-before-answer]
191
+
192
+ ## Accuracy Standards
193
+ - Flag confidence levels when synthesizing across sources
194
+ - Distinguish verified facts from analytical inferences
195
+ - If sources disagree, cite both and explain the discrepancy
196
+ - Never fabricate version numbers, citations, or references
197
+ - When information may be outdated, note this explicitly
198
+
199
+ ## When Uncertain
200
+ State uncertainty explicitly. Ask one clarifying question rather than guessing.
201
+ ```
202
+
203
+ **Generation rules:**
204
+ - Use terminology from Perplexity research, not training-data assumptions
205
+ - Positive framing: "Do X" over "Don't do Y"
206
+ - No few-shot examples (breaks Perplexity)
207
+ - Under 5,000 characters
208
+ - Include Accuracy Standards + When Uncertain (mandatory)
209
+
210
+ Write to `prompts/projects/<project-name>/system-prompt.md`.
211
+
212
+ ### 2d. Auto-condense
213
+
214
+ → Go to **Step 3** (condense to platform outputs)
215
+
216
+ ---
217
+
218
+ ## Step 3 — CONDENSE: Generate platform outputs from system-prompt.md
219
+
220
+ **Triggered when:** standalone project has `system-prompt.md` but missing `space-instructions.md` or `CLAUDE.md`.
221
+
222
+ Read the full `system-prompt.md` as source.
223
+
224
+ ### 3a. Generate Perplexity Space instructions
225
+
226
+ **Target:** `space-instructions.md` | **Budget:** under 4,000 chars
227
+
228
+ **Include:** identity, domain expertise, research domains, source priority, answer format, key frameworks (by name only)
229
+ **Exclude:** internal templates, scoring matrices, reference file content, deployment details, full tables
230
+
231
+ **Output format:**
232
+ ```markdown
233
+ ## Purpose
234
+ ## Domain Expertise
235
+ ## Research Domains
236
+ ## Source Priority
237
+ ## How to Answer
238
+ ## Accuracy Standards
239
+ ```
240
+
241
+ **Perplexity guardrails:**
242
+ - No few-shot examples
243
+ - No URLs in instructions
244
+ - Replace absolute language with conditional ("if available", "when sources confirm")
245
+ - Search-friendly domain terms
246
+
247
+ ### 3b. Generate Claude Code CLAUDE.md (if Claude Code is a target platform)
248
+
249
+ **Target:** `CLAUDE.md` | **Budget:** under 250 lines
250
+
251
+ **Include:** identity, behaviors, domain expertise, frameworks (one-line each), operating modes, quality controls
252
+ **Exclude:** full scoring matrices, templates, reference file content, corporate data tables
253
+
254
+ **Output format:**
255
+ ```markdown
256
+ # [Project Name]
257
+ ## Identity
258
+ ## Behaviors
259
+ ## Domain Expertise
260
+ ## Frameworks
261
+ ## Operating Modes
262
+ ## Quality Controls
263
+ ## References
264
+ ```
265
+
266
+ **Claude Code guardrails:**
267
+ - Positive framing: "Do X" over "Don't do Y"
268
+ - No "CRITICAL: YOU MUST" language (Claude 4.6 overtriggers)
269
+ - Self-check block for quality-critical outputs
270
+ - Reference knowledge files by filename only
271
+
272
+ ### 3c. Validate budgets
273
+
274
+ After generating, check:
275
+ - `space-instructions.md` under 4,000 chars
276
+ - `CLAUDE.md` under 250 lines
277
+
278
+ If over budget: flag and suggest sections to trim.
279
+
280
+ → Go to **Step 4** (results)
281
+
282
+ ---
283
+
284
+ ## Step 4 — RESULTS: Validate + show deployment instructions
285
+
286
+ **Triggered when:** project has outputs to display (compiled or standalone).
287
+
288
+ ### 4a. Run validator
289
+ ```bash
290
+ node bin/prompt-compile.js <project-name>
291
+ ```
292
+
293
+ ### 4b. Show results table
294
+
295
+ ```
296
+ | Output | Chars | Budget | Status |
297
+ |----------------------|--------|--------|--------|
298
+ | system-prompt.md | X | — | Source |
299
+ | project-instructions | X | 2,500 | OK |
300
+ | space-instructions | X | 4,000 | OK |
301
+ | CLAUDE.md | X lines| 250 ln | OK |
302
+ | references/ | N files| — | Upload |
303
+ ```
304
+
305
+ ### 4c. Deployment instructions
306
+
307
+ **Claude Projects (claude.ai):**
308
+ 1. Open project at claude.ai/projects → "Set project instructions"
309
+ 2. Standalone: paste `system-prompt.md` | Compiled: paste `project-instructions.md`
310
+ 3. If `references/` exists: upload each `.md` file as project knowledge
311
+ 4. Save
312
+
313
+ **Perplexity Spaces:**
314
+ 1. Open Space → Settings → Answer Instructions
315
+ 2. Paste `space-instructions.md`
316
+ 3. Save
317
+
318
+ **Claude Code:**
319
+ 1. Copy `CLAUDE.md` to project repo root
320
+
321
+ ### 4d. Offer next actions
322
+ - "Edit the prompt? I'll regenerate platform outputs after."
323
+ - "Want to regenerate? Run `/px-prompt <project-name>` again."
324
+
325
+ ---
326
+
327
+ ## Step 5 — SYNC: Recompile all projects
328
+
329
+ **Triggered when:** `/px-prompt --sync`
330
+
331
+ ```bash
332
+ node bin/prompt-compile.js --all --diff
333
+ ```
334
+
335
+ Show summary table:
336
+ ```
337
+ | Project | CLAUDE.md | Project Instr. | Space Instr. | Changes |
338
+ |---------|-----------|----------------|--------------|---------|
339
+ | praxis | 3,534 | 1,316 ✓ | 1,529 ✓ | none |
340
+ | maximus | — | — | 3,977 ✓ | standalone |
341
+ ```
342
+
343
+ For standalone projects, report validation status instead of compilation status.
344
+
345
+ Print deployment reminders for any project with changes.
346
+
347
+ ---
348
+
349
+ ## Rules
350
+
351
+ ### Always
352
+ - `_base` behaviors (no-flattery, verify, recommend, handle-uncertainty) are included in every project — non-negotiable
353
+ - Accuracy Standards section is mandatory in all Perplexity outputs
354
+ - When Uncertain section is mandatory in all Claude Project outputs
355
+ - Never ask for repo URL, vault path, or git email unless Claude Code is a target platform
356
+
357
+ ### Platform-specific
358
+ - **Perplexity**: no few-shot examples, no URLs, conditional language, search-friendly terms
359
+ - **Claude Code**: positive framing, no "CRITICAL YOU MUST", self-check blocks
360
+ - **Claude Projects**: 5-layer skeleton (Role, Constraints, Format, Knowledge Rules, Failure Handling)
361
+
362
+ ### Generation
363
+ - ALWAYS run Perplexity research before generating system prompts (Step 2)
364
+ - Use current terminology from research, not training-data assumptions
365
+ - Generated prompts are starting points — tell user to review and refine
366
+ - If Perplexity unavailable: proceed with training data, flag for review
367
+
368
+ ### Block matching (compiled mode)
369
+ - Role → identity block: "architect" → `solutions-architect`, "engineer" → `senior-engineer`, "researcher" → `research-partner`
370
+ - Domain keywords → domain blocks: "cloud/azure/aws" → `cloud-infrastructure`, "federal/govcon" → `govcon`, "web/react" → `web-development`
371
+ - If no match: create custom block on the fly
372
+ - Auto-add `official-docs-first` + `flag-confidence` for Perplexity targets
373
+ - Auto-add `vault-integration` + `mcp-servers` + `praxis-workflow` for Claude Code targets
package/bin/praxis.js CHANGED
@@ -141,6 +141,13 @@ async function install() {
141
141
  ok('kits installed');
142
142
  }
143
143
 
144
+ // Copy prompts/ → ~/.claude/prompts/
145
+ const promptsDir = path.join(PKG_DIR, 'prompts');
146
+ if (fs.existsSync(promptsDir)) {
147
+ copyDir(promptsDir, path.join(CLAUDE_DIR, 'prompts'));
148
+ ok('prompt library installed');
149
+ }
150
+
144
151
  // Orphan cleanup: deleted rules and legacy files
145
152
  const orphans = [
146
153
  'obsidian.md', 'security.md',
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const yaml = require('js-yaml');
7
+
8
+ const { BLOCKS_DIR, PROFILES_DIR, parseFrontmatter } = require('../lib/loader');
9
+
10
+ /** Collect all blocks from the blocks directory. */
11
+ function loadAllBlocks() {
12
+ const blocks = [];
13
+ if (!fs.existsSync(BLOCKS_DIR)) return blocks;
14
+
15
+ for (const category of fs.readdirSync(BLOCKS_DIR)) {
16
+ const catDir = path.join(BLOCKS_DIR, category);
17
+ if (!fs.statSync(catDir).isDirectory()) continue;
18
+
19
+ for (const file of fs.readdirSync(catDir)) {
20
+ if (!file.endsWith('.md')) continue;
21
+ const content = fs.readFileSync(path.join(catDir, file), 'utf8');
22
+ const { meta, body } = parseFrontmatter(content);
23
+ const hasCondensed = body.includes('<!-- CONDENSED -->');
24
+ blocks.push({
25
+ id: meta.id || file.replace('.md', ''),
26
+ category,
27
+ platforms: meta.platforms || [],
28
+ charEstimate: meta.char_estimate || null,
29
+ description: meta.description || '',
30
+ tags: meta.tags || [],
31
+ hasCondensed,
32
+ actualChars: body.length,
33
+ file: `prompts/blocks/${category}/${file}`,
34
+ });
35
+ }
36
+ }
37
+ return blocks;
38
+ }
39
+
40
+ /** Collect all profiles and their block references. */
41
+ function loadAllProfiles() {
42
+ const profiles = {};
43
+ if (!fs.existsSync(PROFILES_DIR)) return profiles;
44
+
45
+ for (const file of fs.readdirSync(PROFILES_DIR)) {
46
+ if (!file.endsWith('.yaml')) continue;
47
+ const name = file.replace('.yaml', '');
48
+ const content = yaml.load(fs.readFileSync(path.join(PROFILES_DIR, file), 'utf8'));
49
+ const blockIds = content.blocks
50
+ ? Object.values(content.blocks).filter(Array.isArray).flat()
51
+ : [];
52
+ profiles[name] = { ...content, blockIds };
53
+ }
54
+ return profiles;
55
+ }
56
+
57
+ // ── CLI ──────────────────────────────────────────────────────
58
+
59
+ function main() {
60
+ const args = process.argv.slice(2);
61
+
62
+ if (args.includes('--help')) {
63
+ console.log('Usage: prompt-blocks [options]');
64
+ console.log('Options:');
65
+ console.log(' --category <cat> Filter by category (identity, behaviors, domains, formats, context)');
66
+ console.log(' --profile <name> Show blocks used by a specific profile');
67
+ console.log(' --unused Show blocks not referenced by any profile');
68
+ console.log(' --tags Group output by tags');
69
+ process.exit(0);
70
+ }
71
+
72
+ const blocks = loadAllBlocks();
73
+ const profiles = loadAllProfiles();
74
+
75
+ // Resolve profile inheritance to get full block lists
76
+ for (const [name, profile] of Object.entries(profiles)) {
77
+ if (profile.extends && profiles[profile.extends]) {
78
+ const baseIds = profiles[profile.extends].blockIds || [];
79
+ profile.blockIds = [...new Set([...baseIds, ...profile.blockIds])];
80
+ }
81
+ }
82
+
83
+ // All block IDs referenced by any profile
84
+ const allProfileBlockIds = new Set();
85
+ for (const profile of Object.values(profiles)) {
86
+ for (const id of profile.blockIds) allProfileBlockIds.add(id);
87
+ }
88
+
89
+ // Filter by category
90
+ const catIdx = args.indexOf('--category');
91
+ let filtered = blocks;
92
+ if (catIdx !== -1 && args[catIdx + 1]) {
93
+ const cat = args[catIdx + 1];
94
+ filtered = blocks.filter((b) => b.category === cat);
95
+ }
96
+
97
+ // Filter by profile
98
+ const profIdx = args.indexOf('--profile');
99
+ if (profIdx !== -1 && args[profIdx + 1]) {
100
+ const profName = args[profIdx + 1];
101
+ const profile = profiles[profName];
102
+ if (!profile) {
103
+ console.error(`Profile not found: ${profName}`);
104
+ process.exit(1);
105
+ }
106
+ const profileIds = new Set(profile.blockIds);
107
+ filtered = blocks.filter((b) => profileIds.has(b.id));
108
+ }
109
+
110
+ // Unused mode
111
+ if (args.includes('--unused')) {
112
+ filtered = blocks.filter((b) => !allProfileBlockIds.has(b.id));
113
+ if (filtered.length === 0) {
114
+ console.log('All blocks are referenced by at least one profile.');
115
+ return;
116
+ }
117
+ console.log(`${filtered.length} unused block(s):\n`);
118
+ }
119
+
120
+ // Display
121
+ console.log(`${'ID'.padEnd(28)} ${'Category'.padEnd(12)} ${'Platforms'.padEnd(35)} ${'Chars'.padEnd(8)} Condensed`);
122
+ console.log('-'.repeat(95));
123
+
124
+ for (const block of filtered) {
125
+ const platforms = block.platforms.join(', ') || 'all';
126
+ const chars = block.charEstimate ? String(block.charEstimate) : '—';
127
+ const condensed = block.hasCondensed ? 'yes' : '—';
128
+ console.log(
129
+ `${block.id.padEnd(28)} ${block.category.padEnd(12)} ${platforms.padEnd(35)} ${chars.padEnd(8)} ${condensed}`
130
+ );
131
+ }
132
+
133
+ console.log(`\nTotal: ${filtered.length} blocks`);
134
+
135
+ // Show profile usage summary
136
+ if (!args.includes('--unused') && profIdx === -1) {
137
+ console.log('\nProfile usage:');
138
+ for (const [name, profile] of Object.entries(profiles)) {
139
+ if (name === '_base') continue;
140
+ console.log(` ${name}: ${profile.blockIds.length} blocks`);
141
+ }
142
+ }
143
+ }
144
+
145
+ main();