@esoteric-logic/praxis-harness 2.13.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.
- package/base/CLAUDE.md +7 -1
- package/base/configs/registry.json +4 -2
- package/base/hooks/context7-remind.sh +81 -0
- package/base/hooks/settings-hooks.json +9 -0
- package/base/rules/coding.md +7 -0
- package/base/skills/px-prompt/SKILL.md +373 -0
- package/base/skills/px-research/SKILL.md +13 -0
- package/bin/praxis.js +7 -0
- package/bin/prompt-blocks.js +145 -0
- package/bin/prompt-compile.js +313 -0
- package/kits/web-designer/rules/web-design.md +13 -2
- package/lib/assemblers.js +249 -0
- package/lib/loader.js +148 -0
- package/package.json +10 -3
- package/prompts/blocks/behaviors/flag-confidence.md +13 -0
- package/prompts/blocks/behaviors/handle-uncertainty.md +13 -0
- package/prompts/blocks/behaviors/no-flattery.md +15 -0
- package/prompts/blocks/behaviors/recommend-with-reasons.md +13 -0
- package/prompts/blocks/behaviors/verify-before-reporting.md +13 -0
- package/prompts/blocks/context/mcp-servers.md +12 -0
- package/prompts/blocks/context/official-docs-first.md +16 -0
- package/prompts/blocks/context/praxis-workflow.md +20 -0
- package/prompts/blocks/context/vault-integration.md +13 -0
- package/prompts/blocks/domains/cloud-infrastructure.md +13 -0
- package/prompts/blocks/domains/govcon.md +13 -0
- package/prompts/blocks/domains/web-development.md +13 -0
- package/prompts/blocks/formats/concise-responses.md +13 -0
- package/prompts/blocks/formats/what-so-what-now-what.md +16 -0
- package/prompts/blocks/identity/research-partner.md +10 -0
- package/prompts/blocks/identity/senior-engineer.md +15 -0
- package/prompts/blocks/identity/solutions-architect.md +13 -0
- package/prompts/profiles/_base.yaml +15 -0
- package/prompts/profiles/federal-cloud.yaml +18 -0
- package/prompts/profiles/praxis.yaml +13 -0
- package/prompts/projects/_template/prompt-config.yaml +34 -0
- package/prompts/projects/maximus/prompt-config.yaml +13 -0
- package/prompts/projects/maximus/references/maturity-questions.md +634 -0
- package/prompts/projects/maximus/references/phase-maturity-matrix.md +188 -0
- package/prompts/projects/maximus/references/proposal-writing-standards.md +367 -0
- package/prompts/projects/maximus/space-instructions.md +67 -0
- package/prompts/projects/maximus/system-prompt.md +641 -0
- package/prompts/projects/praxis/CLAUDE.md +84 -0
- package/prompts/projects/praxis/project-instructions.md +24 -0
- package/prompts/projects/praxis/prompt-config.yaml +40 -0
- package/prompts/projects/praxis/space-instructions.md +28 -0
- package/scripts/lint-harness.sh +42 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Replace {{var}} placeholders with values from vars map. */
|
|
4
|
+
function interpolate(text, vars) {
|
|
5
|
+
return text.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
|
|
6
|
+
if (key in vars) return vars[key];
|
|
7
|
+
return `{{${key}}}`;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Check for unresolved {{...}} placeholders. */
|
|
12
|
+
function findUnresolved(text) {
|
|
13
|
+
const matches = text.match(/\{\{(\w+)\}\}/g);
|
|
14
|
+
return matches ? [...new Set(matches)] : [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function assembleClaudeCode(blocks, projectConfig, vars) {
|
|
18
|
+
const lines = [];
|
|
19
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
20
|
+
lines.push(`# ${vars.project || vars.repo_name || 'Project'}`);
|
|
21
|
+
lines.push(`<!-- Generated by Praxis prompt-compile | profile: ${projectConfig.profile} | ${today} -->`);
|
|
22
|
+
lines.push('');
|
|
23
|
+
|
|
24
|
+
// Identity
|
|
25
|
+
const identityBlocks = blocks.filter((b) => b.category === 'identity');
|
|
26
|
+
if (identityBlocks.length > 0) {
|
|
27
|
+
lines.push('## Identity');
|
|
28
|
+
for (const block of identityBlocks) lines.push(block.content, '');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Global Rules reference
|
|
32
|
+
lines.push('## Global Rules');
|
|
33
|
+
lines.push('Inherits execution engine from `~/.claude/CLAUDE.md`.');
|
|
34
|
+
lines.push('');
|
|
35
|
+
|
|
36
|
+
// Git Identity
|
|
37
|
+
if (vars.git_email || vars.git_identity) {
|
|
38
|
+
lines.push('## Git Identity');
|
|
39
|
+
if (vars.git_identity) lines.push(`- **Type**: ${vars.git_identity}`);
|
|
40
|
+
if (vars.git_email) lines.push(`- **Email**: ${vars.git_email}`);
|
|
41
|
+
lines.push('');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Behaviors
|
|
45
|
+
const behaviorBlocks = blocks.filter((b) => b.category === 'behaviors');
|
|
46
|
+
if (behaviorBlocks.length > 0) {
|
|
47
|
+
lines.push('## Behaviors');
|
|
48
|
+
for (const block of behaviorBlocks) lines.push(block.content, '');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Domains
|
|
52
|
+
const domainBlocks = blocks.filter((b) => b.category === 'domains');
|
|
53
|
+
if (domainBlocks.length > 0) {
|
|
54
|
+
lines.push('## Domain Expertise');
|
|
55
|
+
for (const block of domainBlocks) lines.push(block.content, '');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Formats
|
|
59
|
+
const formatBlocks = blocks.filter((b) => b.category === 'formats');
|
|
60
|
+
if (formatBlocks.length > 0) {
|
|
61
|
+
lines.push('## Output Format');
|
|
62
|
+
for (const block of formatBlocks) lines.push(block.content, '');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Tech Stack + Commands (from claude_code_append)
|
|
66
|
+
const append = (projectConfig.overrides || {}).claude_code_append || {};
|
|
67
|
+
if (append.tech_stack) {
|
|
68
|
+
lines.push('## Tech Stack');
|
|
69
|
+
lines.push(append.tech_stack.trim(), '');
|
|
70
|
+
}
|
|
71
|
+
if (append.commands) {
|
|
72
|
+
lines.push('## Commands');
|
|
73
|
+
lines.push('```bash');
|
|
74
|
+
lines.push(append.commands.trim());
|
|
75
|
+
lines.push('```', '');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Context
|
|
79
|
+
const contextBlocks = blocks.filter((b) => b.category === 'context');
|
|
80
|
+
if (contextBlocks.length > 0) {
|
|
81
|
+
for (const block of contextBlocks) lines.push(block.content, '');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Extra notes
|
|
85
|
+
if (append.extra_notes) {
|
|
86
|
+
lines.push('## Important Notes');
|
|
87
|
+
lines.push(append.extra_notes.trim(), '');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Vault Project
|
|
91
|
+
if (vars.vault_project_path) {
|
|
92
|
+
lines.push('## Vault Project');
|
|
93
|
+
lines.push(`- **Vault path**: ${vars.vault_project_path}`);
|
|
94
|
+
lines.push('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Standard footer
|
|
98
|
+
lines.push('## Verification');
|
|
99
|
+
lines.push('- Before marking any task complete, run the test suite');
|
|
100
|
+
lines.push('- Check logs before claiming a bug is fixed');
|
|
101
|
+
lines.push('');
|
|
102
|
+
lines.push('## Conventions');
|
|
103
|
+
lines.push('- **Commits**: conventional commits (feat:, fix:, docs:, refactor:, test:, chore:)');
|
|
104
|
+
lines.push('- **Branches**: `feat/description` or `fix/description`');
|
|
105
|
+
lines.push('');
|
|
106
|
+
lines.push('## Error Learning');
|
|
107
|
+
lines.push('<!-- Add project-specific learnings below -->');
|
|
108
|
+
lines.push('');
|
|
109
|
+
|
|
110
|
+
return lines.join('\n');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function assembleClaudeProject(blocks, projectConfig, vars) {
|
|
114
|
+
const lines = [];
|
|
115
|
+
|
|
116
|
+
// Layer 1: Role
|
|
117
|
+
const identityBlocks = blocks.filter((b) => b.category === 'identity');
|
|
118
|
+
lines.push('## Role');
|
|
119
|
+
if (projectConfig.description) lines.push(projectConfig.description);
|
|
120
|
+
for (const block of identityBlocks) lines.push(block.content);
|
|
121
|
+
lines.push('');
|
|
122
|
+
|
|
123
|
+
// Layer 2: Behavioral Constraints
|
|
124
|
+
const behaviorBlocks = blocks.filter((b) => b.category === 'behaviors');
|
|
125
|
+
if (behaviorBlocks.length > 0) {
|
|
126
|
+
lines.push('## Behavioral Constraints');
|
|
127
|
+
for (const block of behaviorBlocks) lines.push('- ' + block.content);
|
|
128
|
+
lines.push('');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Layer 3: Domain Expertise
|
|
132
|
+
const domainBlocks = blocks.filter((b) => b.category === 'domains');
|
|
133
|
+
if (domainBlocks.length > 0) {
|
|
134
|
+
lines.push('## Domain Expertise');
|
|
135
|
+
for (const block of domainBlocks) lines.push('- ' + block.content);
|
|
136
|
+
lines.push('');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Layer 3b: Output Format
|
|
140
|
+
const formatBlocks = blocks.filter((b) => b.category === 'formats');
|
|
141
|
+
if (formatBlocks.length > 0) {
|
|
142
|
+
lines.push('## Output Format');
|
|
143
|
+
for (const block of formatBlocks) lines.push('- ' + block.content);
|
|
144
|
+
lines.push('');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Additional context
|
|
148
|
+
const append = (projectConfig.overrides || {}).claude_project_append || {};
|
|
149
|
+
if (append.additional_context) {
|
|
150
|
+
lines.push(append.additional_context.trim(), '');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Layer 4: Quality Gates
|
|
154
|
+
if (append.quality_gates) {
|
|
155
|
+
lines.push('## Quality Gates');
|
|
156
|
+
lines.push(append.quality_gates.trim(), '');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Context blocks (workflow, etc.)
|
|
160
|
+
const contextBlocks = blocks.filter((b) => b.category === 'context');
|
|
161
|
+
if (contextBlocks.length > 0) {
|
|
162
|
+
for (const block of contextBlocks) lines.push(block.content);
|
|
163
|
+
lines.push('');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Layer 4b: Knowledge Files (if project has them)
|
|
167
|
+
const knowledgeFiles = projectConfig.knowledge_files || [];
|
|
168
|
+
if (knowledgeFiles.length > 0) {
|
|
169
|
+
lines.push('## Knowledge Files');
|
|
170
|
+
lines.push('Upload these alongside this prompt:');
|
|
171
|
+
for (const kf of knowledgeFiles) {
|
|
172
|
+
lines.push(`- **${kf.file}** — ${kf.description}`);
|
|
173
|
+
}
|
|
174
|
+
lines.push('');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Layer 5: Failure Handling (always present)
|
|
178
|
+
lines.push('## When Uncertain');
|
|
179
|
+
lines.push('State uncertainty explicitly. Ask one clarifying question rather than guessing.');
|
|
180
|
+
lines.push('');
|
|
181
|
+
|
|
182
|
+
return lines.join('\n');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function assemblePerplexitySpace(blocks, projectConfig, vars) {
|
|
186
|
+
const lines = [];
|
|
187
|
+
|
|
188
|
+
// Purpose
|
|
189
|
+
const identityBlocks = blocks.filter((b) => b.category === 'identity');
|
|
190
|
+
lines.push('## Purpose');
|
|
191
|
+
if (projectConfig.description) lines.push(projectConfig.description);
|
|
192
|
+
for (const block of identityBlocks) lines.push(block.content);
|
|
193
|
+
lines.push('');
|
|
194
|
+
|
|
195
|
+
// Source Priority
|
|
196
|
+
const sourceBlocks = blocks.filter(
|
|
197
|
+
(b) => b.category === 'context' && (b.meta.tags || []).includes('sources')
|
|
198
|
+
);
|
|
199
|
+
if (sourceBlocks.length > 0) {
|
|
200
|
+
lines.push('## Source Priority');
|
|
201
|
+
for (const block of sourceBlocks) lines.push(block.content);
|
|
202
|
+
lines.push('');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Domain Expertise
|
|
206
|
+
const domainBlocks = blocks.filter((b) => b.category === 'domains');
|
|
207
|
+
if (domainBlocks.length > 0) {
|
|
208
|
+
lines.push('## Domain Expertise');
|
|
209
|
+
for (const block of domainBlocks) lines.push(block.content);
|
|
210
|
+
lines.push('');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Research Domains
|
|
214
|
+
const append = (projectConfig.overrides || {}).perplexity_space_append || {};
|
|
215
|
+
if (append.research_domains) {
|
|
216
|
+
lines.push('## Research Domains');
|
|
217
|
+
lines.push(append.research_domains.trim(), '');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// How to Answer
|
|
221
|
+
const behaviorBlocks = blocks.filter((b) => b.category === 'behaviors');
|
|
222
|
+
const formatBlocks = blocks.filter((b) => b.category === 'formats');
|
|
223
|
+
if (behaviorBlocks.length > 0 || formatBlocks.length > 0) {
|
|
224
|
+
lines.push('## How to Answer');
|
|
225
|
+
for (const block of behaviorBlocks) lines.push(block.content);
|
|
226
|
+
for (const block of formatBlocks) lines.push(block.content);
|
|
227
|
+
lines.push('');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Anti-hallucination layer (auto-injected for all Perplexity outputs)
|
|
231
|
+
lines.push('## Accuracy Standards');
|
|
232
|
+
lines.push('- Flag your confidence level when synthesizing across sources');
|
|
233
|
+
lines.push('- Distinguish verified facts from analytical inferences');
|
|
234
|
+
lines.push('- If sources disagree, cite both and explain the discrepancy');
|
|
235
|
+
lines.push('- Never fabricate version numbers, API signatures, URLs, or code examples');
|
|
236
|
+
lines.push('- When information may be outdated (>12 months), note the publication date');
|
|
237
|
+
lines.push('- If you cannot find reliable sources, state that clearly rather than speculating');
|
|
238
|
+
lines.push('');
|
|
239
|
+
|
|
240
|
+
return lines.join('\n');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
module.exports = {
|
|
244
|
+
interpolate,
|
|
245
|
+
findUnresolved,
|
|
246
|
+
assembleClaudeCode,
|
|
247
|
+
assembleClaudeProject,
|
|
248
|
+
assemblePerplexitySpace,
|
|
249
|
+
};
|
package/lib/loader.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const yaml = require('js-yaml');
|
|
7
|
+
|
|
8
|
+
const PKG_DIR = path.resolve(__dirname, '..');
|
|
9
|
+
const PROMPTS_DIR = path.join(PKG_DIR, 'prompts');
|
|
10
|
+
const BLOCKS_DIR = path.join(PROMPTS_DIR, 'blocks');
|
|
11
|
+
const PROFILES_DIR = path.join(PROMPTS_DIR, 'profiles');
|
|
12
|
+
|
|
13
|
+
const TARGETS = ['claude-code', 'claude-project', 'perplexity-space'];
|
|
14
|
+
|
|
15
|
+
/** Parse YAML frontmatter from markdown content. Returns { meta, body }. */
|
|
16
|
+
function parseFrontmatter(content) {
|
|
17
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
18
|
+
if (!match) return { meta: {}, body: content.trim() };
|
|
19
|
+
return { meta: yaml.load(match[1]) || {}, body: match[2].trim() };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Read and merge praxis.config.json vars. */
|
|
23
|
+
function loadPraxisConfig() {
|
|
24
|
+
const configPath = path.join(os.homedir(), '.claude', 'praxis.config.json');
|
|
25
|
+
if (!fs.existsSync(configPath)) return {};
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
28
|
+
} catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Merge base profile with child profile. Arrays concat + dedup. */
|
|
34
|
+
function mergeProfiles(base, child) {
|
|
35
|
+
const merged = { ...base, ...child };
|
|
36
|
+
if (base.blocks && child.blocks) {
|
|
37
|
+
merged.blocks = {};
|
|
38
|
+
const allCategories = new Set([
|
|
39
|
+
...Object.keys(base.blocks || {}),
|
|
40
|
+
...Object.keys(child.blocks || {}),
|
|
41
|
+
]);
|
|
42
|
+
for (const cat of allCategories) {
|
|
43
|
+
const baseBlocks = base.blocks[cat] || [];
|
|
44
|
+
const childBlocks = child.blocks[cat] || [];
|
|
45
|
+
merged.blocks[cat] = [...new Set([...baseBlocks, ...childBlocks])];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return merged;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Load a profile by name, resolving single-level extends. */
|
|
52
|
+
function loadProfile(profileName, fail) {
|
|
53
|
+
const profilePath = path.join(PROFILES_DIR, `${profileName}.yaml`);
|
|
54
|
+
if (!fs.existsSync(profilePath)) {
|
|
55
|
+
fail(`Profile not found: ${profilePath}`);
|
|
56
|
+
}
|
|
57
|
+
const profile = yaml.load(fs.readFileSync(profilePath, 'utf8'));
|
|
58
|
+
|
|
59
|
+
if (profile.extends) {
|
|
60
|
+
const basePath = path.join(PROFILES_DIR, `${profile.extends}.yaml`);
|
|
61
|
+
if (!fs.existsSync(basePath)) {
|
|
62
|
+
fail(`Base profile not found: ${basePath}`);
|
|
63
|
+
}
|
|
64
|
+
const base = yaml.load(fs.readFileSync(basePath, 'utf8'));
|
|
65
|
+
return mergeProfiles(base, profile);
|
|
66
|
+
}
|
|
67
|
+
return profile;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Extract FULL and CONDENSED sections from block body. */
|
|
71
|
+
function extractVariants(body) {
|
|
72
|
+
const marker = '<!-- CONDENSED -->';
|
|
73
|
+
const idx = body.indexOf(marker);
|
|
74
|
+
if (idx === -1) return { full: body, condensed: body };
|
|
75
|
+
return {
|
|
76
|
+
full: body.slice(0, idx).trim(),
|
|
77
|
+
condensed: body.slice(idx + marker.length).trim(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Resolve block IDs to file paths, read content, parse. */
|
|
82
|
+
function loadBlocks(profile, target, warn) {
|
|
83
|
+
const blocks = [];
|
|
84
|
+
const blockEntries = profile.blocks || {};
|
|
85
|
+
|
|
86
|
+
for (const [category, blockIds] of Object.entries(blockEntries)) {
|
|
87
|
+
for (const blockId of blockIds) {
|
|
88
|
+
const blockPath = path.join(BLOCKS_DIR, category, `${blockId}.md`);
|
|
89
|
+
if (!fs.existsSync(blockPath)) {
|
|
90
|
+
warn(`Block not found: ${category}/${blockId}.md — skipping`);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const content = fs.readFileSync(blockPath, 'utf8');
|
|
94
|
+
const { meta, body } = parseFrontmatter(content);
|
|
95
|
+
|
|
96
|
+
// Filter by platform
|
|
97
|
+
const platforms = meta.platforms || TARGETS;
|
|
98
|
+
if (!platforms.includes(target)) continue;
|
|
99
|
+
|
|
100
|
+
const variants = extractVariants(body);
|
|
101
|
+
const useCondensed = target !== 'claude-code';
|
|
102
|
+
blocks.push({
|
|
103
|
+
id: meta.id || blockId,
|
|
104
|
+
category,
|
|
105
|
+
content: useCondensed ? variants.condensed : variants.full,
|
|
106
|
+
meta,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return blocks;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Apply project overrides: add/remove blocks. */
|
|
114
|
+
function applyOverrides(profile, overrides) {
|
|
115
|
+
if (!overrides) return profile;
|
|
116
|
+
const modified = { ...profile, blocks: { ...profile.blocks } };
|
|
117
|
+
|
|
118
|
+
if (overrides.add_blocks) {
|
|
119
|
+
for (const [cat, ids] of Object.entries(overrides.add_blocks)) {
|
|
120
|
+
if (!Array.isArray(ids)) continue;
|
|
121
|
+
modified.blocks[cat] = [...new Set([...(modified.blocks[cat] || []), ...ids])];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (overrides.remove_blocks && Array.isArray(overrides.remove_blocks)) {
|
|
126
|
+
for (const blockId of overrides.remove_blocks) {
|
|
127
|
+
for (const cat of Object.keys(modified.blocks)) {
|
|
128
|
+
modified.blocks[cat] = modified.blocks[cat].filter((id) => id !== blockId);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return modified;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = {
|
|
137
|
+
TARGETS,
|
|
138
|
+
BLOCKS_DIR,
|
|
139
|
+
PROFILES_DIR,
|
|
140
|
+
PROMPTS_DIR,
|
|
141
|
+
parseFrontmatter,
|
|
142
|
+
loadPraxisConfig,
|
|
143
|
+
mergeProfiles,
|
|
144
|
+
loadProfile,
|
|
145
|
+
extractVariants,
|
|
146
|
+
loadBlocks,
|
|
147
|
+
applyOverrides,
|
|
148
|
+
};
|
package/package.json
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esoteric-logic/praxis-harness",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"description": "Layered Claude Code harness — workflow discipline, AI-Kits, persistent vault integration",
|
|
5
5
|
"bin": {
|
|
6
6
|
"praxis-harness": "./bin/praxis.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"bin/",
|
|
10
|
+
"lib/",
|
|
10
11
|
"base/",
|
|
11
12
|
"kits/",
|
|
12
13
|
"templates/",
|
|
13
|
-
"scripts/"
|
|
14
|
+
"scripts/",
|
|
15
|
+
"prompts/"
|
|
14
16
|
],
|
|
15
17
|
"scripts": {
|
|
16
|
-
"test": "node --check bin/praxis.js && bash scripts/test-harness.sh"
|
|
18
|
+
"test": "node --check bin/praxis.js && node --check bin/prompt-compile.js && node --check bin/prompt-blocks.js && bash scripts/test-harness.sh",
|
|
19
|
+
"compile-prompts": "node bin/prompt-compile.js --all",
|
|
20
|
+
"list-blocks": "node bin/prompt-blocks.js"
|
|
17
21
|
},
|
|
18
22
|
"repository": {
|
|
19
23
|
"type": "git",
|
|
@@ -28,6 +32,9 @@
|
|
|
28
32
|
],
|
|
29
33
|
"author": "arcanesme",
|
|
30
34
|
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"js-yaml": "4.1.1"
|
|
37
|
+
},
|
|
31
38
|
"engines": {
|
|
32
39
|
"node": ">=18"
|
|
33
40
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: flag-confidence
|
|
3
|
+
description: "Flags confidence levels on factual claims — distinguishes established facts from inferences"
|
|
4
|
+
category: behaviors
|
|
5
|
+
platforms: [perplexity-space, claude-project]
|
|
6
|
+
char_estimate: 120
|
|
7
|
+
tags: [confidence, accuracy]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Flag confidence levels (high/medium/low) on factual claims. Distinguish established facts from inferences. When a claim depends on a single source, say so.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Flag confidence on factual claims. Distinguish facts from inferences. Note single-source claims.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: handle-uncertainty
|
|
3
|
+
description: "Requires explicit uncertainty handling — state what you don't know, ask rather than guess"
|
|
4
|
+
category: behaviors
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 100
|
|
7
|
+
tags: [uncertainty, failure-handling]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
When uncertain, state it explicitly and ask one clarifying question. Never guess or fabricate. If you cannot verify a claim, mark it as unverified.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
When uncertain, say so and ask one clarifying question. Never guess or fabricate.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: no-flattery
|
|
3
|
+
description: "Enforces direct, skeptical communication without filler or self-congratulation"
|
|
4
|
+
category: behaviors
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 120
|
|
7
|
+
tags: [tone, communication]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
No flattery. No filler. Be skeptical. Be concise.
|
|
11
|
+
Never say "looks good" about your own output.
|
|
12
|
+
Every option presented MUST include a recommendation and why.
|
|
13
|
+
|
|
14
|
+
<!-- CONDENSED -->
|
|
15
|
+
No flattery or filler. Be skeptical, concise. Always recommend with reasoning.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: recommend-with-reasons
|
|
3
|
+
description: "Requires recommendations with explicit trade-off reasoning for all options presented"
|
|
4
|
+
category: behaviors
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 130
|
|
7
|
+
tags: [decision-making, communication]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
When presenting options, always include a recommendation and the reasoning behind it. Do not present options without a clear pick. State trade-offs explicitly — cost, complexity, risk, time.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Always recommend with reasoning when presenting options. State trade-offs: cost, complexity, risk, time.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: verify-before-reporting
|
|
3
|
+
description: "Mandates evidence-based reporting — no unverified claims"
|
|
4
|
+
category: behaviors
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 150
|
|
7
|
+
tags: [verification, accuracy]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Verify before you report. Do not claim something works without evidence. Show actual output, not assertions. If you cannot verify, say so explicitly.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Verify before reporting. Show evidence, not assertions. If unverifiable, say so.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: mcp-servers
|
|
3
|
+
description: "Lists available MCP servers and enforces Context7-first documentation lookup"
|
|
4
|
+
category: context
|
|
5
|
+
platforms: [claude-code]
|
|
6
|
+
char_estimate: 120
|
|
7
|
+
tags: [context, mcp, tools]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## MCP Servers
|
|
11
|
+
Available: context7 (live library docs), github (PRs/issues), perplexity (web search).
|
|
12
|
+
Before implementing with any external library: use Context7 first. Training data has a cutoff — Context7 does not.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: official-docs-first
|
|
3
|
+
description: "Prioritizes official documentation and primary sources for Perplexity research"
|
|
4
|
+
category: context
|
|
5
|
+
platforms: [perplexity-space]
|
|
6
|
+
char_estimate: 200
|
|
7
|
+
tags: [context, sources, research]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Source Priority
|
|
11
|
+
1. Official documentation (vendor docs, RFCs, specs)
|
|
12
|
+
2. GitHub repositories (source code, issues, changelogs)
|
|
13
|
+
3. Stack Overflow and community forums (verified answers only)
|
|
14
|
+
4. Blog posts and tutorials (cross-reference with official docs)
|
|
15
|
+
|
|
16
|
+
Always cite sources. Flag when information comes from a single source or may be outdated. Prefer sources published within the last 12 months for actively developed technologies.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: praxis-workflow
|
|
3
|
+
description: "Summarizes the Praxis discuss-plan-execute-verify-simplify-ship workflow"
|
|
4
|
+
category: context
|
|
5
|
+
platforms: [claude-code, claude-project]
|
|
6
|
+
char_estimate: 250
|
|
7
|
+
tags: [context, workflow, praxis]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
Praxis owns the outer loop: discuss → plan → execute → verify → simplify → ship.
|
|
12
|
+
- Start feature work with `/px-discuss` or `/px-next`
|
|
13
|
+
- After implementation: run `/px-simplify` to clean up
|
|
14
|
+
- Use `/px-verify-app` for end-to-end checks
|
|
15
|
+
- Use `/px-ship` when ready to commit + push + PR
|
|
16
|
+
- Pure bugfixes: skip the full loop, use `/px-debug` directly
|
|
17
|
+
- Trivial changes: use `/px-fast` to skip planning
|
|
18
|
+
|
|
19
|
+
<!-- CONDENSED -->
|
|
20
|
+
Workflow: discuss → plan → execute → verify → simplify → ship. Start features with /px-discuss. Bugfixes skip to /px-debug.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: vault-integration
|
|
3
|
+
description: "Configures Obsidian vault integration for persistent project state"
|
|
4
|
+
category: context
|
|
5
|
+
platforms: [claude-code]
|
|
6
|
+
char_estimate: 180
|
|
7
|
+
tags: [context, vault, obsidian]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Vault Project
|
|
11
|
+
- **Path**: {{vault_project_path}}
|
|
12
|
+
- Plans, status, and learnings persist in the vault — decisions not written there do not survive sessions
|
|
13
|
+
- See `~/.claude/rules/vault.md` for backend configuration and file conventions
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: cloud-infrastructure
|
|
3
|
+
description: "Cloud architecture expertise — Azure, AWS, Terraform, networking, identity, cost optimization"
|
|
4
|
+
category: domains
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 180
|
|
7
|
+
tags: [domain, cloud, azure, aws]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Cloud infrastructure expertise: Azure and AWS services, IaC (Terraform, Bicep), networking, identity (Entra ID, IAM), cost optimization, and production operations. Favor managed services over self-hosted when the trade-off is defensible.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Cloud infrastructure: Azure, AWS, Terraform, networking, identity, cost optimization. Favor managed services when defensible.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: govcon
|
|
3
|
+
description: "Government contracting domain — FedRAMP, NIST 800-53, CMMC, Section 508, ATO"
|
|
4
|
+
category: domains
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 200
|
|
7
|
+
tags: [domain, govcon, federal, compliance]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Government contracting domain: FedRAMP, NIST 800-53, CMMC, Section 508 accessibility, ATO processes, and federal acquisition regulations. Compliance is a constraint on every technical decision — surface compliance impact early, not as an afterthought.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
GovCon: FedRAMP, NIST 800-53, CMMC, Section 508, ATO processes. Surface compliance impact on technical decisions early.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: web-development
|
|
3
|
+
description: "Web development expertise — React, Next.js, TypeScript, accessibility, performance"
|
|
4
|
+
category: domains
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 180
|
|
7
|
+
tags: [domain, web, frontend, fullstack]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Web development expertise: React, Next.js, TypeScript, Node.js, modern CSS, accessibility (WCAG 2.1 AA), performance optimization, and responsive design. Semantic HTML first, progressive enhancement, and server-side rendering where SEO or performance demands it.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Web development: React, Next.js, TypeScript, Node.js, CSS, accessibility (WCAG 2.1 AA), performance, responsive design.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: concise-responses
|
|
3
|
+
description: "Scales response length to question complexity — lead with answers, skip preamble"
|
|
4
|
+
category: formats
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 120
|
|
7
|
+
tags: [format, brevity]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Scale response length to question complexity. Short question, short answer. Lead with the answer, not the reasoning. Skip preamble and filler. If you can say it in one sentence, do not use three.
|
|
11
|
+
|
|
12
|
+
<!-- CONDENSED -->
|
|
13
|
+
Match response length to question complexity. Lead with the answer. No preamble or filler.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: what-so-what-now-what
|
|
3
|
+
description: "Structures analysis as What (facts) / So What (impact) / Now What (actions)"
|
|
4
|
+
category: formats
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 160
|
|
7
|
+
tags: [format, structure, reporting]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Structure analysis and status updates as What / So What / Now What:
|
|
11
|
+
- **What**: Facts — what happened or what exists
|
|
12
|
+
- **So What**: Impact — why it matters
|
|
13
|
+
- **Now What**: Action — concrete next steps with owners
|
|
14
|
+
|
|
15
|
+
<!-- CONDENSED -->
|
|
16
|
+
Structure updates as: What (facts) / So What (impact) / Now What (actions with owners).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: research-partner
|
|
3
|
+
description: "Research-focused identity for Perplexity Spaces — primary sources, confidence calibration"
|
|
4
|
+
category: identity
|
|
5
|
+
platforms: [perplexity-space]
|
|
6
|
+
char_estimate: 200
|
|
7
|
+
tags: [identity, research]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
You are a technical research partner. Prioritize primary sources (official docs, RFCs, vendor documentation) over blog posts and tutorials. Flag confidence level when synthesizing across sources. Distinguish between established best practices and emerging patterns.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: senior-engineer
|
|
3
|
+
description: "Core engineering partner identity — think, verify, repair, ask when unclear"
|
|
4
|
+
category: identity
|
|
5
|
+
platforms: [claude-code, claude-project, perplexity-space]
|
|
6
|
+
char_estimate: 200
|
|
7
|
+
tags: [identity, engineering]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
You are a senior engineering partner. Think before you build. Verify before you report. Repair before you proceed.
|
|
11
|
+
If intent is unclear, ask. Do not guess.
|
|
12
|
+
Tell me when I am wrong. If a better approach exists, say so.
|
|
13
|
+
|
|
14
|
+
<!-- CONDENSED -->
|
|
15
|
+
You are a senior engineering partner. Think before you build. Verify before you report. Ask when intent is unclear. Tell me when I am wrong.
|