openhermes 2.6.1 → 4.0.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/CONTEXT.md +18 -0
- package/ETHOS.md +15 -0
- package/README.md +135 -292
- package/bootstrap.mjs +174 -499
- package/harness/agents/openhermes.md +87 -0
- package/harness/codex/CONSTITUTION.md +70 -148
- package/harness/codex/ROUTING.md +126 -0
- package/harness/commands/oh-doctor.md +26 -0
- package/harness/instructions/CONVENTIONS.md +206 -206
- package/harness/instructions/RUNTIME.md +54 -31
- package/harness/skills/oh-builder/SKILL.md +98 -0
- package/harness/skills/oh-caveman/SKILL.md +33 -0
- package/harness/skills/oh-expert/SKILL.md +121 -0
- package/harness/skills/oh-freeze/SKILL.md +28 -0
- package/harness/skills/oh-gauntlet/SKILL.md +119 -0
- package/harness/skills/oh-grill/SKILL.md +77 -0
- package/harness/skills/oh-guard/SKILL.md +33 -0
- package/harness/skills/oh-handoff/SKILL.md +33 -0
- package/harness/skills/oh-health/SKILL.md +90 -0
- package/harness/skills/oh-init/SKILL.md +78 -0
- package/harness/skills/oh-investigate/SKILL.md +35 -0
- package/harness/skills/oh-issue/SKILL.md +36 -0
- package/harness/skills/oh-learn/SKILL.md +28 -0
- package/harness/skills/oh-manifest/SKILL.md +84 -0
- package/harness/skills/oh-plan-review/SKILL.md +128 -0
- package/harness/skills/oh-planner/SKILL.md +157 -0
- package/harness/skills/oh-prd/SKILL.md +35 -0
- package/harness/skills/oh-retro/SKILL.md +33 -0
- package/harness/skills/oh-review/SKILL.md +110 -0
- package/harness/skills/oh-security/SKILL.md +110 -0
- package/harness/skills/oh-ship/SKILL.md +39 -0
- package/harness/skills/oh-skill-craft/SKILL.md +107 -0
- package/harness/skills/oh-skills-link/SKILL.md +29 -0
- package/harness/skills/oh-skills-list/SKILL.md +31 -0
- package/harness/skills/oh-triage/SKILL.md +36 -0
- package/index.mjs +3 -58
- package/lib/harness-resolver.mjs +77 -0
- package/lib/logger.mjs +62 -0
- package/package.json +49 -53
- package/test/plugins-behavioral.test.mjs +64 -0
- package/test/plugins.test.mjs +62 -0
- package/autorecall.mjs +0 -237
- package/curator.mjs +0 -455
- package/harness/commands/build-fix.md +0 -60
- package/harness/commands/checkpoint.md +0 -68
- package/harness/commands/code-review.md +0 -71
- package/harness/commands/doctor.md +0 -42
- package/harness/commands/eval.md +0 -89
- package/harness/commands/go-build.md +0 -87
- package/harness/commands/go-review.md +0 -71
- package/harness/commands/harness-audit.md +0 -90
- package/harness/commands/learn.md +0 -37
- package/harness/commands/loop-start.md +0 -38
- package/harness/commands/loop-status.md +0 -30
- package/harness/commands/memory-search.md +0 -37
- package/harness/commands/model-route.md +0 -32
- package/harness/commands/ohc.md +0 -13
- package/harness/commands/orchestrate.md +0 -88
- package/harness/commands/plan.md +0 -53
- package/harness/commands/quality-gate.md +0 -35
- package/harness/commands/refactor-clean.md +0 -102
- package/harness/commands/rust-build.md +0 -78
- package/harness/commands/rust-review.md +0 -65
- package/harness/commands/security.md +0 -93
- package/harness/commands/setup-pm.md +0 -65
- package/harness/commands/skill-create.md +0 -99
- package/harness/commands/test-coverage.md +0 -80
- package/harness/commands/update-codemaps.md +0 -81
- package/harness/commands/update-docs.md +0 -67
- package/harness/commands/verify.md +0 -68
- package/harness/prompts/architect.txt +0 -189
- package/harness/prompts/build-cpp.md +0 -98
- package/harness/prompts/build-error-resolver.md +0 -44
- package/harness/prompts/build-go.md +0 -340
- package/harness/prompts/build-java.md +0 -140
- package/harness/prompts/build-kotlin.md +0 -137
- package/harness/prompts/build-rust.md +0 -108
- package/harness/prompts/code-reviewer.md +0 -40
- package/harness/prompts/doc-updater.md +0 -206
- package/harness/prompts/docs-lookup.md +0 -71
- package/harness/prompts/e2e-runner.txt +0 -317
- package/harness/prompts/explore.md +0 -42
- package/harness/prompts/harness-optimizer.md +0 -42
- package/harness/prompts/loop-operator.md +0 -53
- package/harness/prompts/planner.md +0 -37
- package/harness/prompts/refactor-cleaner.md +0 -256
- package/harness/prompts/review-cpp.md +0 -81
- package/harness/prompts/review-database.md +0 -261
- package/harness/prompts/review-go.md +0 -257
- package/harness/prompts/review-java.md +0 -113
- package/harness/prompts/review-kotlin.md +0 -143
- package/harness/prompts/review-python.md +0 -101
- package/harness/prompts/review-rust.md +0 -77
- package/harness/prompts/security-reviewer.md +0 -42
- package/harness/prompts/tdd-guide.md +0 -228
- package/harness/rules/audit.md +0 -84
- package/harness/rules/checkpointing.md +0 -75
- package/harness/rules/context-loading.md +0 -33
- package/harness/rules/credential-exposure.md +0 -0
- package/harness/rules/delegation.md +0 -80
- package/harness/rules/handoff.md +0 -267
- package/harness/rules/memory-management.md +0 -28
- package/harness/rules/precedence.md +0 -52
- package/harness/rules/promotion.md +0 -46
- package/harness/rules/ranking.md +0 -64
- package/harness/rules/retrieval.md +0 -94
- package/harness/rules/runtime-guards.md +0 -196
- package/harness/rules/self-heal.md +0 -79
- package/harness/rules/session-start.md +0 -34
- package/harness/rules/skills-management.md +0 -165
- package/harness/rules/state-drift.md +0 -192
- package/harness/rules/verification.md +0 -88
- package/harness/scripts/sync-commands.mjs +0 -259
- package/harness/skills/.bundled_manifest +0 -17
- package/harness/skills/.usage.json +0 -6
- package/harness/skills/api-design/SKILL.md +0 -523
- package/harness/skills/backend-patterns/SKILL.md +0 -598
- package/harness/skills/coding-standards/SKILL.md +0 -549
- package/harness/skills/e2e-testing/SKILL.md +0 -326
- package/harness/skills/frontend-patterns/SKILL.md +0 -642
- package/harness/skills/frontend-slides/SKILL.md +0 -184
- package/harness/skills/security-review/SKILL.md +0 -495
- package/harness/skills/strategic-compact/SKILL.md +0 -131
- package/harness/skills/tdd-workflow/SKILL.md +0 -463
- package/harness/skills/verification-loop/SKILL.md +0 -126
- package/lib/ambient-memory.mjs +0 -167
- package/lib/handoff.mjs +0 -176
- package/lib/hardening.mjs +0 -128
- package/lib/memory-tools-plugin.mjs +0 -365
- package/lib/ohc/block-sync.mjs +0 -69
- package/lib/ohc/compress/search.mjs +0 -152
- package/lib/ohc/compress/state.mjs +0 -76
- package/lib/ohc/config.mjs +0 -186
- package/lib/ohc/message-ids.mjs +0 -168
- package/lib/ohc/notify.mjs +0 -154
- package/lib/ohc/protected-patterns.mjs +0 -54
- package/lib/ohc/prune-apply.mjs +0 -134
- package/lib/ohc/pruner.mjs +0 -610
- package/lib/ohc/reaper.mjs +0 -70
- package/lib/ohc/state.mjs +0 -266
- package/lib/ohc/strategies/deduplication.mjs +0 -72
- package/lib/ohc/strategies/index.mjs +0 -2
- package/lib/ohc/strategies/purge-errors.mjs +0 -43
- package/lib/ohc/token-utils.mjs +0 -26
- package/lib/ohc/updater.mjs +0 -133
- package/lib/paths.mjs +0 -50
- package/lib/schema-validator.mjs +0 -77
- package/lib/search.mjs +0 -48
- package/schemas/audit.schema.json +0 -82
- package/schemas/backlog.schema.json +0 -63
- package/schemas/checkpoint.schema.json +0 -65
- package/schemas/constraint.schema.json +0 -62
- package/schemas/decision.schema.json +0 -63
- package/schemas/instinct.schema.json +0 -63
- package/schemas/loop-state.schema.json +0 -33
- package/schemas/mistake.schema.json +0 -64
- package/schemas/verification_receipt.schema.json +0 -88
- package/skill-builder.mjs +0 -88
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-security
|
|
3
|
+
description: "Security audit: secrets archaeology, dependency supply chain, CI/CD security, OWASP Top 10, STRIDE threat modeling, LLM security. Two modes: daily (8/10 confidence gate) and comprehensive (2/10 bar)."
|
|
4
|
+
tier: 3
|
|
5
|
+
benefits-from: [oh-expert]
|
|
6
|
+
triggers:
|
|
7
|
+
- "security audit"
|
|
8
|
+
- "threat model"
|
|
9
|
+
- "check for vulnerabilities"
|
|
10
|
+
- "owasp review"
|
|
11
|
+
- "pentest"
|
|
12
|
+
- "security review"
|
|
13
|
+
- "cso"
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# oh-security
|
|
17
|
+
|
|
18
|
+
Security audit that finds the doors that are actually unlocked. Two modes: **daily** (8/10 confidence gate — low noise, high signal) and **comprehensive** (2/10 bar — casts a wider net, more findings). Output is a Security Posture Report with severity ratings and remediation plans. Does NOT make code changes — diagnosis only.
|
|
19
|
+
|
|
20
|
+
## Mode Selection
|
|
21
|
+
|
|
22
|
+
- **Daily** (default) — 8/10 confidence gate. Only flag findings with strong evidence. Skips speculative or trace-only checks. Runs all phases but reports only clear findings.
|
|
23
|
+
- **Comprehensive** (`--comprehensive`) — 2/10 bar. Surfaces more. Includes trace-only flags, speculative dependency issues, and historical pattern matching.
|
|
24
|
+
|
|
25
|
+
## Phases
|
|
26
|
+
|
|
27
|
+
### Phase 0: Stack Detection + Architecture Mental Model
|
|
28
|
+
Detect the project's language stack and framework. Build an explicit mental model: what are the components, trust boundaries, data flows, and attack surface.
|
|
29
|
+
|
|
30
|
+
### Phase 1: Attack Surface Census
|
|
31
|
+
Map what an attacker sees:
|
|
32
|
+
- Public vs authenticated vs admin endpoints
|
|
33
|
+
- File upload points, external integrations, background jobs
|
|
34
|
+
- WebSocket channels, webhook receivers
|
|
35
|
+
- CI/CD workflows, container configs, IaC, deploy targets
|
|
36
|
+
|
|
37
|
+
### Phase 2: Secrets Archaeology
|
|
38
|
+
Scan git history for leaked credentials (AWS keys, OpenAI keys, GitHub tokens, Slack tokens, generic secrets). Check `.env` tracking status. Scan CI configs for inline secrets.
|
|
39
|
+
|
|
40
|
+
### Phase 3: Dependency Supply Chain
|
|
41
|
+
Check beyond `npm audit`: known CVEs in direct deps, install scripts in production deps, lockfile integrity, abandoned packages. Diff-mode limits to changed deps.
|
|
42
|
+
|
|
43
|
+
### Phase 4: CI/CD Pipeline Security
|
|
44
|
+
Check for unpinned third-party actions, `pull_request_target` misuse, script injection via `${{ github.event.* }}`, secrets exposed as env vars, CODEOWNERS protection on workflow files.
|
|
45
|
+
|
|
46
|
+
### Phase 5: Infrastructure Shadow Surface
|
|
47
|
+
Dockerfiles (root user, secrets in ARG, missing USER), config files with prod DB URLs, IaC (overly permissive IAM, privileged K8s). Staging configs referencing prod.
|
|
48
|
+
|
|
49
|
+
### Phase 6: Webhook & Integration Audit
|
|
50
|
+
Webhook endpoints without signature verification, TLS verification disabled in prod, overly broad OAuth scopes.
|
|
51
|
+
|
|
52
|
+
### Phase 7: LLM & AI Security
|
|
53
|
+
Prompt injection vectors (user input flowing into system prompts), unsanitized LLM output rendered in UI, tool/function calling without validation, hardcoded AI API keys.
|
|
54
|
+
|
|
55
|
+
### Phase 8: OWASP Top 10 + STRIDE
|
|
56
|
+
Map findings to OWASP Top 10 categories and STRIDE threat model. Identify gaps in coverage across categories.
|
|
57
|
+
|
|
58
|
+
## Output Format
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
Security Posture Report
|
|
62
|
+
══════════════════════
|
|
63
|
+
Project: <name>
|
|
64
|
+
Branch: <branch>
|
|
65
|
+
Mode: daily | comprehensive
|
|
66
|
+
Date: <date>
|
|
67
|
+
|
|
68
|
+
Critical (n):
|
|
69
|
+
- <finding> — <file:line> — <remediation>
|
|
70
|
+
|
|
71
|
+
High (n):
|
|
72
|
+
- <finding> — <file:line> — <remediation>
|
|
73
|
+
|
|
74
|
+
Medium (n):
|
|
75
|
+
- <finding> — <file:line> — <remediation>
|
|
76
|
+
|
|
77
|
+
Low (n):
|
|
78
|
+
- <finding> — <file:line> — <remediation>
|
|
79
|
+
|
|
80
|
+
OWASP Coverage:
|
|
81
|
+
A01:Broken Access Control — n findings
|
|
82
|
+
A02:Cryptographic Failures — n findings
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
STRIDE:
|
|
86
|
+
Spoofing — n
|
|
87
|
+
Tampering — n
|
|
88
|
+
Repudiation — n
|
|
89
|
+
Info Disclosure — n
|
|
90
|
+
Denial of Service — n
|
|
91
|
+
Elevation of Privilege — n
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Rules
|
|
95
|
+
|
|
96
|
+
- **Read-only.** No fixes. Diagnosis only, except for auto-fixable low-severity findings when explicitly asked.
|
|
97
|
+
- **Daily mode** gates findings at 8/10 confidence. If you would not stake your reputation on it, skip it in daily mode.
|
|
98
|
+
- **Comprehensive mode** gates at 2/10. Surface everything plausible. The user decides.
|
|
99
|
+
- **No false positives on git history.** Placeholder values ("your_", "changeme") excluded. Rotated secrets still flagged (they were exposed).
|
|
100
|
+
- **Prioritize by blast radius.** Remote code execution > credential exposure > info leak > best-practice gap.
|
|
101
|
+
- **Always distinguish direct vs transitive** dependencies in supply chain findings.
|
|
102
|
+
- **Use Grep/Glob tools** for searches, not bash grep. The bash blocks below show WHAT to search, not HOW.
|
|
103
|
+
|
|
104
|
+
## Routing
|
|
105
|
+
|
|
106
|
+
| Outcome | Route |
|
|
107
|
+
|---------|-------|
|
|
108
|
+
| pass | → [report findings to user] |
|
|
109
|
+
| fail | → oh-investigate (deepen on findings) |
|
|
110
|
+
| blocker | → surface to user |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-ship
|
|
3
|
+
description: "Deploy and PR pipeline — test, bump, changelog, PR, deploy, verify"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# oh-ship
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
When code is ready to ship. Runs the full release pipeline from test to PR to deploy verification.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
1. **Pre-flight** — run test suite, lint, typecheck
|
|
13
|
+
2. **Version bump** — read VERSION file or package.json, bump according to semver
|
|
14
|
+
3. **Changelog** — generate from commit history since last tag. Polish voice: consistent tense, group by type (features, fixes, breaking)
|
|
15
|
+
4. **Commit + push** — create release commit with changelog
|
|
16
|
+
5. **PR** — create GitHub PR with summary, test evidence, deploy plan
|
|
17
|
+
6. **Merge** — merge PR after CI passes
|
|
18
|
+
7. **Deploy** — trigger deploy (platform-specific)
|
|
19
|
+
8. **Verify** — canary check, health endpoints, smoke tests
|
|
20
|
+
9. **Post-ship docs sync** — read all project docs (README, ARCHITECTURE.md, CONTRIBUTING.md), cross-reference the diff, update to match what shipped:
|
|
21
|
+
- README: new features, changed APIs, updated examples
|
|
22
|
+
- CHANGELOG: verify polish against what actually merged
|
|
23
|
+
- ARCHITECTURE.md / CONTRIBUTING.md: reflect any structural or workflow changes
|
|
24
|
+
- TODOS.md: remove completed items, add any new deferred items discovered during ship
|
|
25
|
+
- VERSION file: bump if not already done
|
|
26
|
+
|
|
27
|
+
## Anti-patterns
|
|
28
|
+
- Skipping pre-flight checks ("just a quick fix")
|
|
29
|
+
- Bumping version without changelog
|
|
30
|
+
- Deploying without post-deploy verification
|
|
31
|
+
- Not tagging releases
|
|
32
|
+
|
|
33
|
+
## Routing
|
|
34
|
+
|
|
35
|
+
| Outcome | Route |
|
|
36
|
+
|---------|-------|
|
|
37
|
+
| pass | → oh-retro (post-ship review) |
|
|
38
|
+
| fail | → oh-expert (diagnose deployment failure) |
|
|
39
|
+
| blocker | → surface to user |
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-skill-craft
|
|
3
|
+
description: "Create new agent skills with proper structure, frontmatter, progressive disclosure, and bundled resources. Meta-skill for growing the harness."
|
|
4
|
+
tier: 2
|
|
5
|
+
benefits-from: [oh-expert]
|
|
6
|
+
triggers:
|
|
7
|
+
- "create a skill"
|
|
8
|
+
- "write a skill"
|
|
9
|
+
- "new skill"
|
|
10
|
+
- "skill-craft"
|
|
11
|
+
- "meta-skill"
|
|
12
|
+
- "add a capability"
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# oh-skill-craft
|
|
16
|
+
|
|
17
|
+
Create new agent skills for the OpenHermes harness. Skills are the unit of progressive disclosure — loaded on demand, not preloaded.
|
|
18
|
+
|
|
19
|
+
## Skill Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
harness/skills/<oh-name>/
|
|
23
|
+
├── SKILL.md # Main instructions (required)
|
|
24
|
+
├── REFERENCE.md # Detailed docs (if SKILL.md exceeds 100 lines)
|
|
25
|
+
└── scripts/ # Utility scripts (if deterministic operations needed)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## SKILL.md Template
|
|
29
|
+
|
|
30
|
+
```markdown
|
|
31
|
+
---
|
|
32
|
+
name: oh-<name>
|
|
33
|
+
description: "Brief description. Use when [specific triggers]."
|
|
34
|
+
tier: <2|3|4>
|
|
35
|
+
benefits-from: [<skill-dependencies>]
|
|
36
|
+
triggers:
|
|
37
|
+
- "<trigger phrase>"
|
|
38
|
+
- "<another trigger>"
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# oh-<name>
|
|
42
|
+
|
|
43
|
+
<one-paragraph summary>
|
|
44
|
+
|
|
45
|
+
## When to Use
|
|
46
|
+
|
|
47
|
+
<when to invoke this skill>
|
|
48
|
+
|
|
49
|
+
## Workflow
|
|
50
|
+
|
|
51
|
+
1. <step>
|
|
52
|
+
2. <step>
|
|
53
|
+
3. <step>
|
|
54
|
+
|
|
55
|
+
## Anti-patterns
|
|
56
|
+
|
|
57
|
+
- <anti-pattern 1>
|
|
58
|
+
- <anti-pattern 2>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Description Requirements
|
|
62
|
+
|
|
63
|
+
The description is the only thing the agent sees when deciding which skill to load. Make it actionable:
|
|
64
|
+
|
|
65
|
+
**Good:** "Create new agent skills with proper structure, frontmrmatter, and bundled resources. Use when user wants to create, write, or build a new skill."
|
|
66
|
+
|
|
67
|
+
**Bad:** "Helps with skills."
|
|
68
|
+
|
|
69
|
+
## Field Guide
|
|
70
|
+
|
|
71
|
+
| Frontmatter Field | Required | Purpose |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| `name` | yes | Must match `^[a-z0-9]+(-[a-z0-9]+)*$` and directory name |
|
|
74
|
+
| `description` | yes | Max 200 chars. First sentence = what it does. Second = when to use. |
|
|
75
|
+
| `tier` | no | 2=tool, 3=strategic, 4=autonomous. Controls preamble verbosity. |
|
|
76
|
+
| `benefits-from` | no | Skill dependencies. Listed skills should be loaded first. |
|
|
77
|
+
| `triggers` | no | Natural language patterns that should route to this skill. |
|
|
78
|
+
|
|
79
|
+
## When to Add Scripts
|
|
80
|
+
- Operation is deterministic (validation, formatting)
|
|
81
|
+
- Same code would be generated repeatedly
|
|
82
|
+
- Errors need explicit handling
|
|
83
|
+
|
|
84
|
+
Scripts save tokens and improve reliability vs generated code.
|
|
85
|
+
|
|
86
|
+
## When to Split Files
|
|
87
|
+
- SKILL.md exceeds 100 lines
|
|
88
|
+
- Content has distinct domains
|
|
89
|
+
- Advanced features are rarely used (put in REFERENCE.md)
|
|
90
|
+
|
|
91
|
+
## Review Checklist
|
|
92
|
+
|
|
93
|
+
- [ ] Description includes triggers ("Use when...")
|
|
94
|
+
- [ ] SKILL.md under 100 lines
|
|
95
|
+
- [ ] No time-sensitive info (dates, versions, deprecation warnings)
|
|
96
|
+
- [ ] Consistent oh- prefix and terminology
|
|
97
|
+
- [ ] Concrete examples included
|
|
98
|
+
- [ ] Anti-patterns documented
|
|
99
|
+
- [ ] Tests still pass after adding (`npm test`)
|
|
100
|
+
|
|
101
|
+
## Routing
|
|
102
|
+
|
|
103
|
+
| Outcome | Route |
|
|
104
|
+
|---------|-------|
|
|
105
|
+
| pass | → oh-skills-link (verify skill discovery) |
|
|
106
|
+
| fail | → oh-expert (diagnose skill creation issues) |
|
|
107
|
+
| blocker | → surface to user |
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-skills-link
|
|
3
|
+
description: "Verify that OpenCode can discover the package-local skills directory"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# oh-skills-link
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
After installing new skills or updating existing ones. Verifies that OpenCode can discover the package-local skills directory.
|
|
10
|
+
|
|
11
|
+
## Workflow
|
|
12
|
+
1. Read skills from `harness/skills/`
|
|
13
|
+
2. Confirm `config.skills.paths` points at the package-local harness path
|
|
14
|
+
3. Skip unchanged skills when checking manifests
|
|
15
|
+
4. Log missing, invalid, or newly added skills
|
|
16
|
+
|
|
17
|
+
## Anti-patterns
|
|
18
|
+
- Linking skills without verifying they exist in harness
|
|
19
|
+
- Copying skills into global config during normal operation
|
|
20
|
+
- Overwriting user-modified skills without explicit intent
|
|
21
|
+
- Linking broken or incomplete skills
|
|
22
|
+
|
|
23
|
+
## Routing
|
|
24
|
+
|
|
25
|
+
| Outcome | Route |
|
|
26
|
+
|---------|-------|
|
|
27
|
+
| pass | → [report link status to user] |
|
|
28
|
+
| fail | → oh-skill-craft (fix or rebuild broken skill) |
|
|
29
|
+
| blocker | → surface to user |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-skills-list
|
|
3
|
+
description: "List all available oh-* skills with descriptions"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# oh-skills-list
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
To discover what skills are available. Lists every skill with its name, description, and category.
|
|
10
|
+
|
|
11
|
+
## Output
|
|
12
|
+
Markdown table of skills:
|
|
13
|
+
|
|
14
|
+
| Skill | Description | Category |
|
|
15
|
+
|-------|-------------|----------|
|
|
16
|
+
| oh-plan | Strategy + architecture review | Orchestration |
|
|
17
|
+
| oh-qa | Full QA workflow | Quality |
|
|
18
|
+
| ... | ... | ... |
|
|
19
|
+
|
|
20
|
+
## Anti-patterns
|
|
21
|
+
- Listing "all available" but missing recently installed skills
|
|
22
|
+
- Showing skill file paths instead of human-readable descriptions
|
|
23
|
+
- Not categorising skills (flat list is hard to scan)
|
|
24
|
+
|
|
25
|
+
## Routing
|
|
26
|
+
|
|
27
|
+
| Outcome | Route |
|
|
28
|
+
|---------|-------|
|
|
29
|
+
| pass | → [done — read-only report] |
|
|
30
|
+
| fail | → [surface issue to user] |
|
|
31
|
+
| blocker | → surface to user |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-triage
|
|
3
|
+
description: "Issue triage state machine — classify, prioritise, assign"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# oh-triage
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
When new issues come in, or when reviewing the issue backlog. Drives issues through a triage state machine.
|
|
10
|
+
|
|
11
|
+
## States
|
|
12
|
+
1. **Needs triage** — new issue, unclassified
|
|
13
|
+
2. **Needs info** — waiting on reporter for clarification
|
|
14
|
+
3. **Ready for agent** — well-specified, can be picked up
|
|
15
|
+
4. **Ready for human** — needs human judgment or access
|
|
16
|
+
5. **Wontfix** — declined with reason
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
1. Read new issues (label: `needs-triage`)
|
|
20
|
+
2. Classify: bug / feature / enhancement / question
|
|
21
|
+
3. Assess severity and priority
|
|
22
|
+
4. Assign to appropriate state and owner
|
|
23
|
+
5. Add triage metadata labels
|
|
24
|
+
|
|
25
|
+
## Anti-patterns
|
|
26
|
+
- Leaving issues in "needs triage" indefinitely
|
|
27
|
+
- Triaging without reading the full issue
|
|
28
|
+
- Wontfix without explanation (leaves reporter unhappy)
|
|
29
|
+
|
|
30
|
+
## Routing
|
|
31
|
+
|
|
32
|
+
| Outcome | Route |
|
|
33
|
+
|---------|-------|
|
|
34
|
+
| pass | → oh-issue (publish triaged issues) or oh-handoff (pass to agent) |
|
|
35
|
+
| fail | → oh-expert (clarify ambiguous issue) |
|
|
36
|
+
| blocker | → surface to user |
|
package/index.mjs
CHANGED
|
@@ -1,58 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { BootstrapPlugin } from "./bootstrap.mjs"
|
|
5
|
-
import { MemoryToolsPlugin } from "./lib/memory-tools-plugin.mjs"
|
|
6
|
-
import { AmbientMemoryPlugin } from "./lib/ambient-memory.mjs"
|
|
7
|
-
import { OhcPlugin } from "./lib/ohc/pruner.mjs"
|
|
8
|
-
import { UpdaterPlugin } from "./lib/ohc/updater.mjs"
|
|
9
|
-
|
|
10
|
-
function chain(...fns) {
|
|
11
|
-
const h = fns.filter(Boolean)
|
|
12
|
-
if (!h.length) return undefined
|
|
13
|
-
if (h.length === 1) return h[0]
|
|
14
|
-
return async (i, o) => { for (const fn of h) await fn(i, o) }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default async (input) => {
|
|
18
|
-
const results = await Promise.allSettled([
|
|
19
|
-
BootstrapPlugin(input),
|
|
20
|
-
AutorecallPlugin(input),
|
|
21
|
-
CuratorPlugin(input),
|
|
22
|
-
SkillBuilderPlugin(input),
|
|
23
|
-
MemoryToolsPlugin(input),
|
|
24
|
-
AmbientMemoryPlugin(input),
|
|
25
|
-
OhcPlugin(input),
|
|
26
|
-
UpdaterPlugin(input),
|
|
27
|
-
])
|
|
28
|
-
const [bootstrap, autorecall, curator, skillBuilder, memoryTools, ambient, ohc, updater] = results.map(r => r.status === 'fulfilled' ? r.value : {})
|
|
29
|
-
|
|
30
|
-
const merged = {}
|
|
31
|
-
|
|
32
|
-
if (bootstrap.config) merged.config = bootstrap.config
|
|
33
|
-
|
|
34
|
-
const toolHandlers = { ...memoryTools.tool, ...ohc.tool }
|
|
35
|
-
if (Object.keys(toolHandlers).length) merged.tool = toolHandlers
|
|
36
|
-
|
|
37
|
-
merged["experimental.chat.system.transform"] = chain(ohc["experimental.chat.system.transform"])
|
|
38
|
-
merged["experimental.chat.messages.transform"] = chain(
|
|
39
|
-
ambient["experimental.chat.messages.transform"],
|
|
40
|
-
bootstrap["experimental.chat.messages.transform"],
|
|
41
|
-
ohc["experimental.chat.messages.transform"],
|
|
42
|
-
)
|
|
43
|
-
merged["command.execute.before"] = chain(updater["command.execute.before"], ohc["command.execute.before"])
|
|
44
|
-
|
|
45
|
-
const eventHandlers = [autorecall.event, curator.event, skillBuilder.event].filter(Boolean)
|
|
46
|
-
if (eventHandlers.length) {
|
|
47
|
-
merged.event = async (payload) => {
|
|
48
|
-
await Promise.allSettled(eventHandlers.map(fn => fn(payload)))
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
for (const hook of ["experimental.session.compacting", "tool.execute.after"]) {
|
|
53
|
-
const handler = chain(curator[hook], skillBuilder[hook])
|
|
54
|
-
if (handler) merged[hook] = handler
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return merged
|
|
58
|
-
}
|
|
1
|
+
import { BootstrapPlugin } from "./bootstrap.mjs"
|
|
2
|
+
|
|
3
|
+
export default BootstrapPlugin
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Shared harness directory resolver — canonical implementation.
|
|
2
|
+
// Extracted from bootstrap.mjs to eliminate DRY violation with goal-tracker.mjs.
|
|
3
|
+
// Both consumers import from here.
|
|
4
|
+
|
|
5
|
+
import path from "node:path"
|
|
6
|
+
import fs from "node:fs"
|
|
7
|
+
import { fileURLToPath } from "node:url"
|
|
8
|
+
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
const PKG_DIR = path.resolve(__dirname, "..")
|
|
11
|
+
|
|
12
|
+
const REQUIRED_HARNESS_FILES = [
|
|
13
|
+
["codex", "CONSTITUTION.md"],
|
|
14
|
+
["instructions", "RUNTIME.md"],
|
|
15
|
+
["skills", "oh-plan", "SKILL.md"],
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
function ancestorDirs(start, limit = 6) {
|
|
19
|
+
const dirs = []
|
|
20
|
+
let current = path.resolve(start)
|
|
21
|
+
for (let i = 0; i < limit; i++) {
|
|
22
|
+
dirs.push(current)
|
|
23
|
+
const parent = path.dirname(current)
|
|
24
|
+
if (parent === current) break
|
|
25
|
+
current = parent
|
|
26
|
+
}
|
|
27
|
+
return dirs
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildHarnessCandidates(currentDir, execPath, cwd) {
|
|
31
|
+
const roots = [path.resolve(currentDir, "harness")]
|
|
32
|
+
const seen = new Set(roots)
|
|
33
|
+
|
|
34
|
+
const anchors = [path.dirname(execPath), path.dirname(path.dirname(execPath)), cwd]
|
|
35
|
+
for (const anchor of anchors) {
|
|
36
|
+
for (const dir of ancestorDirs(anchor)) {
|
|
37
|
+
for (const root of [
|
|
38
|
+
path.join(dir, "harness"),
|
|
39
|
+
path.join(dir, "node_modules", "openhermes", "harness"),
|
|
40
|
+
path.join(dir, "bin", "node_modules", "openhermes", "harness"),
|
|
41
|
+
]) {
|
|
42
|
+
const normalized = path.normalize(root)
|
|
43
|
+
if (seen.has(normalized)) continue
|
|
44
|
+
seen.add(normalized)
|
|
45
|
+
roots.push(normalized)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return roots
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function hasRequiredHarnessFiles(root) {
|
|
54
|
+
return REQUIRED_HARNESS_FILES.every(parts => fs.existsSync(path.join(root, ...parts)))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveHarnessRoot({
|
|
58
|
+
currentDir = PKG_DIR,
|
|
59
|
+
execPath = process.execPath,
|
|
60
|
+
cwd = process.cwd(),
|
|
61
|
+
candidateRoots,
|
|
62
|
+
} = {}) {
|
|
63
|
+
const roots = candidateRoots ?? buildHarnessCandidates(currentDir, execPath, cwd)
|
|
64
|
+
for (const root of roots) {
|
|
65
|
+
if (hasRequiredHarnessFiles(root)) return root
|
|
66
|
+
}
|
|
67
|
+
return path.resolve(currentDir, "harness")
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let _harnessDir
|
|
71
|
+
|
|
72
|
+
export function setHarnessRootForTest(dir) { _harnessDir = dir }
|
|
73
|
+
|
|
74
|
+
export function getHarnessDir() {
|
|
75
|
+
if (!_harnessDir) _harnessDir = resolveHarnessRoot()
|
|
76
|
+
return _harnessDir
|
|
77
|
+
}
|
package/lib/logger.mjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import os from "node:os"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
|
|
5
|
+
const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 }
|
|
6
|
+
const CURRENT_LEVEL = LEVELS[process.env.OPENCODE_LOG_LEVEL?.trim().toLowerCase()] ?? (process.env.OPENHERMES_LOG_LEVEL?.trim().toLowerCase() === "debug" ? LEVELS.debug : LEVELS.warn)
|
|
7
|
+
|
|
8
|
+
const LOG_DIR = path.join(os.homedir(), ".local", "share", "opencode", "log")
|
|
9
|
+
const LOG_FILE = path.join(LOG_DIR, "openhermes.log")
|
|
10
|
+
|
|
11
|
+
function ts() {
|
|
12
|
+
const d = new Date()
|
|
13
|
+
return `${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2,"0")}-${d.getDate().toString().padStart(2,"0")} ${d.getHours().toString().padStart(2,"0")}:${d.getMinutes().toString().padStart(2,"0")}:${d.getSeconds().toString().padStart(2,"0")}.${d.getMilliseconds().toString().padStart(3,"0")}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function formatArgs(args) {
|
|
17
|
+
return args.map(a => {
|
|
18
|
+
if (a === null) return "null"
|
|
19
|
+
if (a === undefined) return "undefined"
|
|
20
|
+
if (typeof a === "object") {
|
|
21
|
+
try { return a?.message || JSON.stringify(a) } catch { return String(a) }
|
|
22
|
+
}
|
|
23
|
+
return String(a)
|
|
24
|
+
}).join(" ")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function shouldLog(levelName) {
|
|
28
|
+
return LEVELS[levelName] >= CURRENT_LEVEL
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let _fd = null
|
|
32
|
+
function getFd() {
|
|
33
|
+
if (_fd) return _fd
|
|
34
|
+
try {
|
|
35
|
+
fs.mkdirSync(LOG_DIR, { recursive: true })
|
|
36
|
+
_fd = fs.openSync(LOG_FILE, "a")
|
|
37
|
+
} catch {
|
|
38
|
+
_fd = -1
|
|
39
|
+
}
|
|
40
|
+
return _fd
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createLogger(name) {
|
|
44
|
+
const prefix = `[openhermes:${name}]`
|
|
45
|
+
|
|
46
|
+
function emit(levelName, ...args) {
|
|
47
|
+
if (!shouldLog(levelName)) return
|
|
48
|
+
const fd = getFd()
|
|
49
|
+
if (fd < 0) return
|
|
50
|
+
const line = `${ts()} ${prefix} [${levelName.toUpperCase()}] ${formatArgs(args)}\n`
|
|
51
|
+
try { fs.writeSync(fd, line) } catch {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
debug: (...args) => emit("debug", ...args),
|
|
56
|
+
info: (...args) => emit("info", ...args),
|
|
57
|
+
warn: (...args) => emit("warn", ...args),
|
|
58
|
+
error: (...args) => emit("error", ...args),
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const rootLogger = createLogger("root")
|
package/package.json
CHANGED
|
@@ -1,53 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "openhermes",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"main": "./index.mjs",
|
|
8
|
-
"dependencies": {
|
|
9
|
-
"@opencode-ai/plugin": "1.14.46"
|
|
10
|
-
},
|
|
11
|
-
"exports": {
|
|
12
|
-
".": "./index.mjs",
|
|
13
|
-
"./
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"harness/"
|
|
27
|
-
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"test": "node --test"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
"homepage": "https://github.com/nathwn12/openhermes#readme",
|
|
52
|
-
"author": "nathwn12"
|
|
53
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "openhermes",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "OpenCode-native skills, commands, and rules orchestration for OpenHermes.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./index.mjs",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@opencode-ai/plugin": "1.14.46"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./index.mjs",
|
|
13
|
+
"./bootstrap": "./bootstrap.mjs"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"index.mjs",
|
|
17
|
+
"bootstrap.mjs",
|
|
18
|
+
"ETHOS.md",
|
|
19
|
+
"CONTEXT.md",
|
|
20
|
+
"lib/",
|
|
21
|
+
"test/",
|
|
22
|
+
"harness/codex/",
|
|
23
|
+
"harness/instructions/",
|
|
24
|
+
"harness/skills/",
|
|
25
|
+
"harness/commands/",
|
|
26
|
+
"harness/agents/"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "node --test test/*.test.mjs"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"opencode",
|
|
33
|
+
"openhermes",
|
|
34
|
+
"orchestrator",
|
|
35
|
+
"skills",
|
|
36
|
+
"commands",
|
|
37
|
+
"agents",
|
|
38
|
+
"rules"
|
|
39
|
+
],
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/nathwn12/openhermes.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/nathwn12/openhermes/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/nathwn12/openhermes#readme",
|
|
48
|
+
"author": "nathwn12"
|
|
49
|
+
}
|