'Skill architect and builder. Designs, builds, and validates complete Agent Skill packages through a mandatory eight-phase pipeline: existence gate, research, classify, scope, architecture, plan, build, validate. Default output is the finished installable package. Not for skill evaluation (use skilllab''s Critique procedure) or variant proposals (use ocas-mentor).'
Resources
8Install
npx skillscat add indigokarasu/forge Install via the SkillsCat registry.
nargs='[]'is invalid in argparse — When defining command-line arguments,nargs='[]'is not a valid option and will cause a ValueError. To accept zero or more arguments, usenargs='*'instead. This caused the run_dispatch_pipeline.py script to fail until corrected.
Forge is the system's skill architect — given a capability idea or broken existing package, it runs a mandatory eight-phase internal pipeline covering existence gate, research, classification, scoping, architecture, planning, construction, and validation before writing a single file. The default output is the finished, installable package with all file contents written; Forge never returns design briefs or plans in place of the real artifact.
When to Use
- Building new OCAS skills from scratch
- Skill architecture and design review
- Bulk skill library updates and synchronization
- Skill consolidation and deprecation
- When a new capability needs a permanent skill home
- Create a new Agent Skill from a goal or capability description
- Review or critique an existing skill package
- Repair broken or defective skill packages
- Validate a skill package against OCAS standards
When NOT to Use
- One-off task execution (use the appropriate existing skill)
- Skill evaluation/scoring (use Mentor or skilllab)
- Content generation or research
- System health monitoring (use Custodian)
- Authentication and service wiring (use ocas-auth)
- Building non-skill artifacts
- Web research — use Sift
- Skill structure reference / frontmatter template lookup — use
write-a-skillfor quick
reference on field requirements, file layout, and description conventions. Forge is for building.
Responsibility boundary
Forge owns skill design, construction, consolidation, update verification,
compliance auditing, and repo-sync. Forge's forge.validate handles quick
structural checks; deep quality scoring and iterative improvement is now
owned by skilllab (Critique procedure, merged from ocas-critique).
Forge does not own: skill quality scoring and iteration (skilllab), skill
evaluation or variant testing (Mentor), behavioral pattern analysis,
behavioral refinement (Praxis), experimentation (Fellow), system health and
skill initialization (Custodian), runtime orchestration and delegation (the
agent harness), authentication and MCP wiring (ocas-auth).
Note on review-skill vs skilllab's Critique: The 3rd-party review-skill
(agentskill-sh) provides lightweight quick-check scoring. skilllab's Critique
procedure is the full OCAS quality engine with 6-phase pipeline, batch mode,
iteration loops, and autonomous improvement. Use skilllab for all OCAS skill
scoring. Use review-skill only for quick structural checks on non-OCAS
skills. Never
push review-skill to GitHub — it's 3rd-party.
Forge receives VariantProposal and VariantDecision files from Mentor. It builds variant packages and applies promotion decisions.
Ontology types
Forge does not extract user entities and does not emit Chronicle signals. Forge operates on skill package data and skill metadata only, not on user entities from Chronicle or Weave.
Commands
forge.build— design, scope, build, and validate a complete skill packageforge.critique— review a package and identify defectsforge.repair— fix broken files in an existing packageforge.classify— classify a proposed skill (shortcut, workflow, system)forge.validate— run validation checks on a packageforge.scaffold— generate a minimal package skeletonforge.consolidate— merge an orphan or duplicate skill into its natural parentforge.verify-update— check whether a skill is at the latest version from its GitHub sourceforge.sync— sync local skill changes to the canonical repository via PRforge.audit— audit one or more skills for OCAS compliance, apply fixes, and sync to GitHubforge.status— current build state if multi-step build in progressforge.journal— write journal for the current run; called at end of every runforge.update— pull latest from GitHub source; preserves journals and data
Mandatory design pipeline
Run all phases before writing files. Full phase detail including existence gates
(parent search, standalone test, absorption test), research (skill library → GitHub search → deep-read → compare),
classification, scoping, architecture, plan, build, and validation procedures: seereferences/design_pipeline.md.
Key rule: absorption first. If an existing skill already owns the domain,
add content to it as a references/ doc or scripts/ file — do not create a
new skill. See references/enforcement_durability.md for the absorption
decision framework.
Research rule: After the existence gate passes, you MUST research before
classifying. Search GitHub repos (via gh search repos) AND search the skill
library (via the APIs below) to understand what already exists. The goal is
NOT to copy existing skills but to understand how they work and synthesize
that knowledge into a new, better skill. Review at least 10 repos or skills
before deciding to build.
Naming and Authorship Rules
See references/naming-and-authorship.md for the full naming convention and authorship tagging rules. Key points:
- Never create
ocas-*or rename toocas-*/util-*without explicit user authorization. - Auto-generated skills must use
author: autogeneratedin metadata. - Auto-generated thin wrappers are candidates for deletion — see references for criteria.
Skill type classification
- Shortcut — narrow tool wrapper. 20-120 line SKILL.md.
- Workflow — multi-step process. 80-250 line SKILL.md.
- System — durable behavior system. 150-300 line SKILL.md, deeper material in references.
Package rules
Minimum package: SKILL.md with agentskills.io frontmatter. Add references/, scripts/, assets/ only when justified. Read references/enforcement_durability.md for full guidance on how to make rules durable across updates. See also references/package_patterns.md for package shape guidance and references/authoring_rules.md for full authoring standards.
Run completion
After every Forge command (build, critique, repair, validate, audit):
- Check
{agent_root}/commons/data/ocas-forge/for unprocessed VariantProposal and VariantDecision JSON files. Cross-reference proposal IDs againstintake/processed/andprocessed/directories to skip already-processed files. Process any new files — build variant packages, apply fixes, or queue for Mentor evaluation as appropriate. After processing, move files toprocessed/. - Check journal payload fields (see interfaces specification) for VariantProposal and VariantDecision files from Mentor received via journal; process and move to the consumer's ingestion log.
- Persist build log entries and decisions to local JSONL files.
- Log material decisions to
decisions.jsonl. - Write journal via
forge.journal.
When to apply fixes directly vs. build variants: If a proposal has strong evidence (≥3 consecutive proposals for the same issue, ≥50 runs analyzed, ≥7 days of consistent data, and the fix is low-risk), Forge may apply the fix directly without a full A/B evaluation cycle. Otherwise, queue for Fellow evaluation. Document the rationale in the action journal.
Cross-platform portability
Skills that hardcode ~/.hermes/ paths will NOT work on other agent harnesses (OpenClaw, Claude Code, Cursor, etc.). When building a new skill:
- Use
{agent_root}as the base for all paths inside the skill's storage layout diagrams. This variable resolves to whatever harness the skill runs on. - NEVER hardcode
~/.hermes/in file paths, storage diagrams, or operational descriptions. Even for Hermes-native skills, use{agent_root}/sessions/,{agent_root}/skills/,{agent_root}/references/instead. - Mention the target harness in the frontmatter with a
requires:field if the skill depends on Hermes-specific tools (memory,skill_manage,session_search,cronjob). Example:requires: hermes. This tells other harnesses to skip the skill. - Document Hermes-specific tool dependencies in a "Required tools" section so future porters know what to adapt.
Anti-patterns to reject
- Skipping research on skill improvement. Phase 1.5 (Research) is mandatory for ALL forge operations — not just new builds. When asked to "improve" or "update" an existing skill, you MUST still research external sources (GitHub, arxiv, community patterns) to find new patterns, techniques, and taxonomies that could improve the skill. The user correction "did you do the research phase?" is a signal that you skipped Phase 1.5. Research is not optional just because the skill already exists — the whole point of improvement is to find what you don't already know.
- Vague or overly broad scope
- Generic descriptions that don't route well
- SKILL.md bloated with background explanation
- Support folders created for aesthetics
- Plans returned instead of packages
- Template residue and placeholders
- Storage inside skill package directories
- Undocumented inter-skill interfaces
## Integrated:wrapper sections: when folding content into a parent skill, do NOT wrap it in## Integrated:sections. Refactor the content into the parent's existing section structure instead.- Advisory-only enforcement doesn't work: writing "use Forge instead of skill_manage" in MEMORY.md is advisory and easily skipped. The hard gates must be in the Forge SKILL.md itself (phase 1 checks A/B/C), because that's the artifact that gets loaded and followed. Never rely on memory notes as the sole enforcement mechanism for behavioral rules.
Gotchas
Fixed argparse nargs error in run_dispatch_pipeline.py — Changed
nargs='[]'tonargs='*'for the --new-files argument to accept zero or more arguments. This fixed a ValueError that occurred when the script was called during dispatch processing.Stale files in
processed/vsintake/processed/— check both locations during journal-scanMissing
includes:in frontmatter — required when references/ or scripts/ dir existsScope boundary for sync —
forge.sync/forge.auditonly onocas-*skillsDoing more than asked — match work to the scope of the request
Incorrect Naming — NEVER create/rename
ocas-*without user authorizationNon-durable fixes — put rules in skill's own git repo or MEMORY.md, not hermes core
Runaway repo creation — check for 3rd-party skills before
gh repo createYAML block scalar truncation —
description: >/|contain newlines; useread_file+patchactionfield is polymorphic in forge journals — guard withisinstancebefore every accessDispatcher
new_filespaths lack prefix — check both profile-scoped and commons pathsAppending to JSONL files — ALWAYS use
echo >>, NEVER heredoc with>write_fileescapes quotes in Python files — useterminal()with heredoc for .py filesPlaceholder-then-patch anti-pattern — never write placeholder strings intending to fix later
Heredoc
$(date)timestamp mismatch — compose TS into a variable first, use for both filename and contentResearch is not optional for improvements — MUST run Phase 1.5 research before touching files
forge.updatevsgit pulldivergence — cross-check git log against SKILL.md version fieldforge_audit_skills.pyis a non-functional stub — The script atscripts/forge_audit_skills.pyonly prints "Forge skill audit starting (dry_run=...)" and exits with a# TODO: Implement compliance auditcomment. It produces NO output file and performs NO checks. Whenforge.auditis invoked, the agent must perform the full audit manually: scan the skill directory, check for SKILL.md presence, read frontmatter, verify cross-references, and identify orphans. Do NOT wait for or look for a report file from this script. Confirmed 2026-06-29: full manual audit of 65+ skills required.nargs='[]'is invalid in argparse — When defining command-line arguments,nargs='[]'is not a valid option and will cause a ValueError. To accept zero or more arguments, usenargs='*'instead. This caused the run_dispatch_pipeline.py script to fail until corrected.nargs='[]'is invalid in argparse — When defining command-line arguments,nargs='[]'is not a valid option and will cause a ValueError. To accept zero or more arguments, usenargs='*'instead. This caused the run_dispatch_pipeline.py script to fail until corrected.
The Forge build pipeline: existence gate → research → classify → scope → architecture → plan → build → validate.
- Existence gate — check if skill already exists
- Research — search GitHub, arxiv, skill registries for patterns
- Classify — determine skill type and scope
- Scope — define boundaries and interfaces
- Architecture — design the package structure
- Plan — create implementation plan
- Build — implement the skill
- Validate — run critique and verify 50/50
Inter-skill interfaces
Forge reads variant proposals and decisions from Mentor journals.
File types received:
{proposal_id}.json— VariantProposal{decision_id}.json— VariantDecision
After processing each file, move to the consumer's ingestion log.
See references/interfaces.md for full handoff contracts.
Storage layout
See references/storage-layout.md.
OKRs
See references/okrs.md.
Optional skill cooperation
- Critique (skilllab) — the evaluation complement to Forge's build pipeline
- Mentor — receives VariantProposal and VariantDecision files via journal payload
- Fellow — Forge may build experiment harnesses for Fellow benchmarks
- Custodian — initializes skills built by Forge during system health passes
- Chronicle — skill metadata and journal entries ingested for knowledge persistence
Journal outputs
Action Journal — every build, critique, repair, validation, audit, and variant processing run.
Initialization
On first invocation of any Forge command, run forge.init. Creates data
directories, writes default config, registers the forge.update cron job, and
logs the initialization decision. See references/init_procedure.md for the
exact sequence.
Dispatch / Cron Integration
When triggered by dispatcher or forge:journal-scan cron:
- Check for unprocessed
vp_*.json/vd_*.jsonin data root,proposals/,intake/ - Cross-reference against
intake/processed/andprocessed/to skip already-processed files - Process new files: build variants, apply fixes, queue for Mentor
- Move processed files to
processed/ - If no unprocessed files: write no-op journal and exit
- Perform phantom file cleanup: After every dispatch run, ls journal directories and check for files with empty timestamp fields, double timestamps, or malformed names. Rename/fix any phantom files. See
references/phantom-file-cleanup.mdfor details and warnings about false positives.
Multi-skill dispatch: Forge runs independently — scan for variants, write no-op if clean. Don't block on sibling skills.
Explicit dispatch prompt overrides the no-op shortcut (confirmed 2026-07-07): When the dispatcher's type is new_journals and its prompt contains an EXPLICIT instruction to run the pipelines (e.g., "run Forge journal scan", "run Mentor light heartbeat", "run Praxis journal ingest"), that instruction takes precedence over the dispatch-pipeline-guide's genuine-no-op shortcut. Even if every new_file is already content-evaluated in praxis eval and all content is routine, the pipelines must still be executed — the run itself is the deliverable. Expected outcome: all resolve to no-op (Forge: 0 unprocessed proposals → forge-scan no_op journal; Mentor: self-referencing heartbeat; Praxis: only Bug-2 noise lessons + no_signal events). After running, still write the pipeline output journals (forge-scan, praxis-dispatch, the heartbeat's mentor-light) and apply third-wave eval mitigation — do NOT suppress them, because the pipelines actually executed and produced real output journals. The shortcut applies only to routine re-detections (second-wave / dispatch.wave meta-journals) with no explicit run instruction.
Second-wave detection: If journal timestamp is BEFORE dispatch detected_at → second-wave. Write no-op. If ANY new_file not in eval file → genuine dispatch, run full pipeline.
Consolidated reference: The multi-skill dispatch workflow is now documented in references/dispatch-pipeline-guide.md. Read this before running any dispatch pipeline for the canonical decision procedure.
Eval file gap edge case (confirmed 2026-06-26 dispatch #142): Even when
last_ingest_runis set to a timestamp AFTER a journal's file timestamp, that journal can still be MISSING from the eval file. The Praxis state'slast_ingest_runis updated at the END of a dispatch wave, but individual journals from that wave may not have been added if the eval check was skipped. Fix: During second-wave handling, ALWAYS check each dispatchernew_fileindividually against the eval file withgrep -q "filename" eval_file— never assumelast_ingest_runcoverage. If a journal is missing from eval file, add it before writing no-op journals. Seereferences/session-20260626-dispatch-027-forge.md.Cron journal eval gap (confirmed 2026-06-26 dispatch #143): Cron pipeline journals (
praxis-cron-*,mentor-light-*from cron source) can also be missing from the eval file during second-wave detection. These are NOT dispatch-output journals — they're written by the cron pipeline between dispatch waves. One journal from a cron cycle may be present while another from the same cycle is absent (e.g.,mentor-light-063212Zin eval butpraxis-cron-063348Zmissing). Fix: During second-wave, check ALLnew_fileentries against the eval file regardless ofsourcefield (dispatcher vs cron). Add any missing cron journals before writing no-op journals. Third-wave scope for this pattern: Add 7+ journals — 3 from current dispatch wave, 3 from detected dispatch wave, plus all missing cron journals from prior cycles. Seereferences/session-20260626-dispatch-143-forge.md.Partial cycle gap between sibling pipelines (confirmed 2026-06-26 dispatch #146): A sub-variant of the cron journal gap where one cron pipeline's journal is in the eval file but another cron pipeline's journal from the SAME cycle is absent. Example:
mentor-light-20260626T073205Zpresent in eval, butpraxis-cron-20260626T073343Z(written 90 seconds later by the cron pipeline) missing. Root cause: Praxis cron ingest processed the mentor journal but completed before the praxis-cron journal was written, or the eval check only covered journals already in the state'slast_ingest_runwindow. Fix: Same universal rule —grep -q "filename" journals_evaluated.jsonlfor EVERYnew_fileindividually, regardless of whether sibling journals from the same cycle are already present. Never infer that "if mentor-light is evaluated, praxis-cron from the same cycle must be too."Dispatch-output eval gap (confirmed 2026-06-26 dispatch #144): Prior dispatch wave's own output journals (
forge-scan-*,praxis-dispatch-*) can be missing from the eval file even when a sibling journal from the same wave IS present (e.g.,mentor-light-070339Zin eval butforge-scan-070643Zandpraxis-dispatch-070643Zmissing). Root cause: The prior wave's Praxis ingest may evaluate only the mentor-light journal but not the forge-scan/praxis-dispatch journals before the ingest completes.last_ingest_runtimestamp (07:06:55) is AFTER journal file timestamps (07:06:43), creating false confidence of coverage. Fix: During second-wave, always grep eachnew_fileindividually against the eval file — never assume same-wave journals share eval status. Add missing dispatch-output journals before writing no-op journals. Seereferences/session-20260626-dispatch-144-forge.md.Post-ingest cron gap (confirmed 2026-06-26 dispatch #145): Cron journals created AFTER
last_ingest_runbut BEFORE the next dispatch wave are missing from the eval file. The state'slast_ingest_runreflects the last ingest OPERATION timestamp, not the last journal CREATION. Between waves, the cron pipeline continues writing new journals that the state doesn't know about. Fix: Same as other eval gap variants — grep eachnew_fileindividually against the eval file. This is the same root cause as the cron journal gap (#141, #143) but with a different trigger timing. Seereferences/session-20260626-dispatch-145-forge.md.Hybrid second-wave with stale cron gap (confirmed 2026-06-26 dispatch #152): A second-wave dispatch can contain BOTH self-referential dispatch-output journals (correctly in eval) AND stale cron journals from prior cycles that were missed by ALL prior waves. Example: 4 of 5 "new" files are our own dispatch-output (in eval), but 1 is
mentor-light-20260626T084028Z.jsonfrom a prior cron cycle — NOT in eval. Response: Add the missing cron journal(s) to eval file, advancelast_ingest_run, but do NOT write additional dispatch-output journals (that would create third-wave noise). The rule: second-wave = add gaps + advance state, never write new journals. Seereferences/session-20260626-dispatch-152-forge.md.Combined before-ingest + dispatch-output gap (confirmed 2026-06-26 dispatch #159): A genuine dispatch where the dispatcher's
new_filesare BEFORElast_ingest_run(pattern #4) AND a prior wave's dispatch-output journal is ALSO missing from eval (pattern #6). Both are caught by the per-journal grep. The broaderfindscan may reveal additional post-ingest cron gaps (pattern #3). Response: Full pipeline execution. Backfill ALL gaps found (dispatcher new_files + prior wave output + cron gaps). Apply third-wave mitigation for current dispatch output. This combination is normal when a prior wave's Praxis ingest completed before the forge-scan/praxis-dispatch journals were written. Seereferences/session-20260626-dispatch-159-forge.md.Third-wave mitigation scope:
Third-wave self-referential pattern (confirmed 2026-06-22): After a multi-skill dispatch, the dispatcher re-scans and detects journals written by the dispatch's own run (forge-scan, praxis-dispatch, mentor-light). This is the second wave — expected and harmless if journals are already in Praxis's eval file. But a third wave can occur when the forge-scan or praxis-dispatch journal is written AFTER the Praxis ingest updates
last_ingest_run. These journals have mtimes after the state timestamp, so the dispatcher detects them as "new" again. Mitigation: After the Praxis ingest completes, the caller must also add all dispatch-output journals (especially forge-scan) tojournals_evaluated.jsonland advancelast_ingest_runpast their mtimes. Seereferences/session-20260622-dispatch.md.Phantom file cleanup pattern (confirmed 2026-06-25 dispatch #100, 2026-06-26 dispatch #150): When writing JSON journals via
python3 -cinsideterminal(), f-string curly braces{}can be silently consumed by bash's${}expansion, producing files with empty or corrupted names (e.g.,forge-scan-.json). Double timestamps can also occur (e.g.,dispatch-20260626T20260626T082335Z.json) when shell variable interpolation duplicates the timestamp. After every dispatch run,lsthe journal directory and check for files with empty timestamp fields, double timestamps, or malformed names. Rename/fix any phantom files before they get detected as "new" by the next dispatcher scan. Beware false positives: during 2026, timestamps in the 20:xx:xx hour range (e.g.,T202602Z= 20:26:02) will contain "2026" in the time portion — this is valid, not a phantom. Seereferences/phantom-file-cleanup.md.Path typo:
oras-praxisvsocas-praxis(confirmed 2026-06-29 dispatch): When constructing the Praxis data directory path, a single-character typo (oras-praxisinstead ofocas-praxis) causescpandpython3to fail with "No such file or directory". Fix: The canonical path is/root/.hermes/profiles/indigo/commons/data/ocas-praxis/— always verify withls -d /root/.hermes/profiles/indigo/commons/data/oca*before constructing script paths. The skill name isocas-(withs), notora-. Confirmed:cp template /root/.../oras-praxis/script.pyfailed silently, thenpython3 /root/.../oras-praxis/script.pyraised FileNotFoundError. When usingcat > file << EOFinsideterminal(), any commands placed AFTER the JSON/YAML content but BEFORE theEOFdelimiter are treated as heredoc body text and written into the file. Example:cat > "$DIR/file.json" << EOF\n{...json...}\necho "Written: ..."\ncat "$DIR/file.json" | python3 -c "..."\nEOF— theechoandcatlines end up inside the JSON file, corrupting it. Fix: Never place commands after the file content in a heredoc. If you need to verify the file, do it in a SEPARATEterminal()call. Better yet, usewrite_filefor JSON/YAML — it's atomic, validates syntax, and can't leak trailing commands. Confirmed 2026-06-26:forge-scan-20260626T014859Z.jsoncontained valid JSON followed byecho "Written: ..."andcat ... | python3 ...lines.execute_codeis blocked in cron mode — When running as a scheduled cron job,execute_codeis rejected with: "BLOCKED: execute_code runs arbitrary local Python (including subprocess calls that bypass shell-string approval checks). Cron jobs run without a user present to approve it." Fix: Useterminal()with a heredoc Python script instead:python3 << 'PYEOF'\n...code...\nPYEOF. This is the cron-safe way to run multi-step Python that walks filesystems, builds sets, or processes JSON. Confirmed 2026-06-26 dispatch: Praxis journal ingest scan (walk 10k+ files, compute set difference) had to useterminal()heredoc instead ofexecute_code.write_fileline-wrapping corrupts Python (confirmed 2026-06-30T10:20Z) — Thewrite_filetool silently wraps long lines (~80 chars), splitting Python string literals and variable assignments mid-token. Example:"/root/.hermes/profiles/indigo/..."becomes"/rootfiles/indigo/..."and two separateVAR = "..."assignments merge into one corrupted line. Fix: After writing Python viawrite_file, runpython3 -c "import py_compile; py_compile.compile('/tmp/script.py', doraise=True)"before executing. For scripts >30 lines, write to/tmp/, compile-check, then run. Seereferences/dispatch-pipeline-guide.md§ write_file line-wrapping corrupts Python.run_dispatch_pipeline.pyPython 3.14 compatibility — Previously experienced issues related to argparse nargs configuration (fixed by usingnargs='*'instead of invalidnargs='[]'). Verified working correctly on Python 3.14 in dispatch scenarios as of 2026-06-30.Praxis-cron double-Z timestamp bug still active — The Praxis cron ingest script continues to produce journals with double-Z suffixes (e.g.,
praxis-cron-20260630T092758ZZ.json). Root cause ists.rstrip('Z') + 'Z'applied to a value already ending in Z. Mitigation: dispatch pipeline treats these filenames as-is for eval registration. Fix needed inpraxis_ingest_run.py/praxis_common.py. Confirmed 2026-06-30.Inline Python blocks compose their own timestamps independently of prior shell
TSvariables — When a Forge/Mentor/Praxis pipeline writes journals in oneterminal()call (using a shellTS=$(date ...)variable) and then runs eval/third-wave logic in a SEPARATEterminal()call with inline Python, the Python block'sdatetime.now()diverges from the shellTS. Third-wave eval entries then use the Python timestamp for journal IDs that were written with the shell timestamp — producing phantom entries referencing non-existent files. Fix: Compose ALL timestamps inside the SAME Python block, or write actual journal filenames to a temp file so subsequent steps read them verbatim. Never carry a shellTSacrossterminal()boundaries and assume inline Python will match it. Confirmed 2026-06-29 dispatch.Dispatcher new_file vs heartbeat output journal divergence (confirmed 2026-06-29T04:40Z): When a dispatch triggers a Mentor heartbeat, two mentor-light journals exist: (1) the dispatcher's
new_file(e.g.,mentor-light-043547Z— written by a prior cron heartbeat) and (2) the current heartbeat's output (e.g.,mentor-light-044551Z— written by the script we just ran). Third-wave mitigation typically registers only journal #2 because it scans for recently-written files. Journal #1 (the dispatcher's originalnew_file) is a DIFFERENT file that also needs eval registration. Fix: After third-wave mitigation, ALWAYS re-grep each dispatchernew_fileindividually against the eval file. If any are missing, register them withaction_taken: "dispatch_new_journal_registration". Do NOT assume that registering the heartbeat's output covers the dispatcher's input — they are distinct files with distinct timestamps. Confirmed:mentor-light-043547Zwas missed on first pass and caught by verification grep.Post-dispatch cleanup can trigger massive legacy backfill — The post-dispatch cleanup does a full
os.walkof the journals directory and registers every.jsonfile not in the eval file. If the eval file was created after journals started accumulating (mid-June 2026), the first cleanup will register hundreds or thousands of legacy files at once. This is a one-time event — after the initial backfill, only new journals will be caught. The eval file growing by 800+ entries in a single dispatch is normal for the first cleanup after eval tracking begins. Do NOT treat this as an error or re-processing event. Confirmed 2026-06-26 dispatch #160: 865 legacy files backfilled.State file timestamp double-Z suffix — When composing a timestamp like
20260626T%H%M%SZin Python and appending"Z", the result can be20260626T103652ZZif the format string already includedZ. Fix:ts.rstrip('Z') + 'Z'. Prevention: Compose the timestamp once in a shell variable (TS=$(date -u +%Y%m%dT%H%M%SZ)) and reuse it for both filename and content. Never embed the timestamp in two separate string compositions. Confirmed 2026-06-26 dispatch #160:ingest_state.jsonhadlast_ingest_run: "20260626T103652ZZ".Cross-skill journal gap (confirmed 2026-06-26 dispatch #154): After completing the standard Praxis ingest (processing the dispatcher's
new_files), a broader gap can exist: journals from skills NOT in the dispatcher's detection scope, written by cron pipelines with non-standard filename conventions (e.g.,ocas-rallyusesjrn_YYYYMMDD_HHMMSS.jsoninstead of*-dispatch-*or*-light-*). These journals have timestamps betweenlast_ingest_runand "now" but were never detected by the dispatcher. Fix: After the standard ingest completes, run a finalfindfor ANY.jsonfile in{agent_root}/commons/journals/with mtime afterlast_ingest_runthat is NOT in the eval file. This catches cross-skill journals the dispatcher missed. Always do this before writing the dispatch-output journals (third-wave mitigation). Seereferences/session-20260626-dispatch-154-forge.md.Post-dispatch cron journal gap (confirmed 2026-06-26 dispatch #155): After completing all 3 pipelines, backfilling eval gaps, AND applying third-wave mitigation, a cron pipeline can write additional journals between our eval backfill and our third-wave mitigation. These journals are NOT in the eval file and WILL be detected as "new" by the next dispatch. Root cause: The cron pipeline runs independently of the dispatch pipeline. Between the moment we read the eval file and the moment we add own-output journals, the cron pipeline can write new journals. Detection: After writing all dispatch-output journals and third-wave mitigation entries, do ONE MORE
findfor any.jsonfile with mtime afterlast_ingest_runthat is NOT in the eval file. Response: Add any found entries to the eval file with sourcepost-dispatch-cleanup. Do NOT trigger another dispatch or re-processing — just append to eval and advancelast_ingest_run. Seereferences/session-20260626-dispatch-155-forge.md.Complete eval gap pattern catalog (7 patterns, confirmed 2026-06-26):
# Pattern Journal vs last_ingest_run Gap Cause 1 Cron journal gap (#143) AFTER Ingest ran before journal was written 2 Tight eval gap (#151) AFTER Ingest ran between cron cycles 3 Post-ingest cron gap (#145) AFTER Cron writes after ingest completes 4 Before-ingest cron gap (#153) BEFORE Ingest didn't re-evaluate pre-existing journals 5 Cross-skill gap (#154) ANY Dispatcher misses non-standard naming 6 Dispatch-output gap (#144) AFTER Prior wave's own journals missed 7 Post-dispatch cron gap (#155) AFTER Cron writes between our backfill and third-wave mitigation Eval file entries must use relative paths — When writing to
journals_evaluated.jsonl, thejournalandfilenamefields MUST be relative to{agent_root}/commons/journals/(e.g.,ocas-forge/2026-06-26/forge-scan-TS.json). Never use absolute paths (/root/.hermes/profiles/indigo/commons/journals/...). Absolute paths break the dispatcher's grep-based eval checks and cause false "gap" detection on subsequent dispatches. Confirmed 2026-06-26: third-wave mitigation wrote 3 entries with absolute paths, which had to be post-hoc corrected.grep -cin shell conditionals produces unexpected exit codes —grep -creturns count0AND exit code 1 when no matches found. Incount=$(grep -c ...) ; if [ "$count" -eq 0 ], the[test may behave unexpectedly with newline in output. Fix: Usegrep -q "pattern" filefor boolean checks (no output, correct exit code). Or usegrep "pattern" file > /dev/null 2>&1then check$?. Never parsegrep -coutput as a variable for arithmetic comparison. Confirmed 2026-06-26 dispatch #142:grep -creturned0\n0(two lines) due to shell quoting, causing[ "0\n0" -eq 0 ]to fail with "integer expected".Verification grep false negative from
$(date)micro-differences — When verifying that dispatch-output journals are in the eval file, the eval entry's timestamp may differ from the journal filename's timestamp by seconds (each is generated by a separate$(date)call). Agrep "forge-scan-20260626T092740Z"check fails if the eval entry hasT092806Z. Fix: Use partial timestamp matching for verification:grep "forge-scan-20260626T0927"(drop the last 2-3 chars of the timestamp). Or usegrep -q "dispatch-third-wave-mitigation"to find all third-wave entries regardless of timestamp. Confirmed 2026-06-26 dispatch #156.ingest_state.jsonin dispatchernew_filesis not a journal — The dispatcher listsocas-praxis/ingest_state.jsoninnew_fileson every genuine dispatch because its mtime updates when state advances. This is NOT a journal that needs eval tracking — it's a state file. The eval file should already have an entry for it from the first dispatch that processed it. If grep confirms it's already in the eval file, skip it. If somehow missing, add it with sourcestate-file-initbut do NOT treat its presence as evidence of a genuine dispatch — it's always "new" because it's always being updated. Confirmed 2026-06-26 dispatch #157.Eval entry path base:
commons/journals/not profile root — When constructingjournal_idforjournals_evaluated.jsonl, useos.path.relpath(fpath, "commons/journals")NOTos.path.relpath(fpath, "."). The latter produces paths prefixed withcommons/journals/which fail all grep lookups and cause false "gap" detection on every subsequent dispatch. Confirmed 2026-06-26: post-dispatch cleanup wrote a mismatched entry that had to be manually corrected. Seereferences/session-20260626-dispatch-wave-second-wave-path-fix.md.read_filereturns stale/wrong state content — ALWAYS use Pythonjson.load()for state files — Theread_filetool may return the commons-scoped copy, a cached version, or a file with a different schema than the profile-scopedingest_state.json. In dispatch ~#161,read_fileshowedlast_ingest_run: "20260626T104320Z"with fields likedispatch_waveandeval_file_total, while Pythonjson.load()on the same path returnedlast_ingest_run: "2026-06-26T10:36:03.950989+00:00"with completely different fields (journals_evaluated_count,note, etc.). Trustingread_filewould have caused misclassification as second-wave and missed 11 genuine journals. Fix: Always read state files viapython3 << 'PYEOF'heredoc withjson.load(). Never useread_filefor JSON state that drives dispatch decisions. Cron-safe pattern:python3 -c "import json; s=json.load(open('/root/.hermes/profiles/indigo/commons/data/ocas-praxis/ingest_state.json')); print(s['last_ingest_run'])". Confirmed 2026-06-26 dispatch ~#161.journals_evaluated_countdrift (confirmed 2026-06-26 dispatch ~#165) — Theingest_state.jsonjournals_evaluated_countandlast_eval_file_linefields only increment by what the current dispatch explicitly adds. Post-dispatch cleanup entries (sourcepost-dispatch-cleanup) are appended to the eval file without updating these counters. Over multiple dispatches, the state counter diverges from the actual eval file line count (e.g., state said 39603 while eval file had 39737 lines — a 134-entry drift). Fix: After post-dispatch cleanup completes, do a finalwc -l(or Python line count) of the eval file and set bothjournals_evaluated_countandlast_eval_file_lineto the actual count. Not critical for correctness (grep checks are authoritative), but keeps diagnostics accurate.~does NOT expand incdinsideterminal()— When usingterminal(), the tilde~is NOT expanded by bash incd ~/pathcommands. Use absolute paths:cd /root/.hermes/profiles/indigo/skills/ocas-forge. Confirmed 2026-06-29:cd ~/.hermes/...failed with "No such file or directory".Inline Python typo pitfall (
state_counttruncation + import shadowing + double-assignment) — When writing multi-step gap backfill scripts as inline Python interminal(), three specific errors have bitten the pipeline: (1) Truncated dict key likestate_count']instead ofstate['journals_evaluated_count']causes SyntaxError. (2) Mixingimport datetimewithfrom datetime import datetimecausesAttributeErrorondatetime.now(). (3) Chained dict assignment likestate["k1"] =["k2"] = val→SyntaxError: cannot assign to literal(cannot chain-assign to dict keys — use one line per assignment). Fix: Local variables for dict keys; onlyfrom datetime import datetime, timezone; never chain-assign to dict keys. Confirmed 2026-06-30T10:35Z dispatch.**JSON journal writing in cron: prefer shell heredoc — When writing JSON journal files, inline Python heredocs (
python3 << 'PYEOF'with dict literals containing double-quotes) suffer from (1) smart-quote corruption by the heredoc parser, (2) variable name truncation when identifiers appear immediately after closing quotes, (3)SyntaxError: invalid decimal literalfrom mangled dict literals. Fix: For output, use shell heredoc with pre-composedTS=$(date -u +%Y%m%M%SZ)and$NOWvariables. Reserve Python heredocs for eval file reads/writes where content is built programmatically (no raw double-quoted JSON). Confirmed 2026-06-30T11:25Z dispatch (6 consecutive failures before switching to shell heredoc). Seereferences/session-20260630-dispatch-1125Z-forge.md.Pure eval-registration dispatch (confirmed 2026-06-30T11:25Z) — A dispatch variant where ALL
new_filesneed eval registration but NONE require pipeline skill loading. Detection: allnew_filesare either (a) already in praxis eval but missing from dispatch eval (bridge case), or (b) prior-wave dispatch-wave artifacts (timestamp < detected_at). Response: Grep eachnew_fileagainst both eval files → register missing entries directly → write dispatch-wave journal withclassification: "mixed_genuine_no_op"→ advancelast_ingest_run→ skip all pipeline skills. Do NOT load Forge/Mentor/Praxis or runpraxis_ingest_run.py. Thejournals_evaluated_countin state does NOT change (no praxis eval entries added). Seereferences/session-20260630-dispatch-1125Z-forge.md.
Self-update
forge.update pulls the latest package from the source: URL in frontmatter.
Runs silently unless version changed or error.
Drift detection procedure (added 2026-06-23, extended 2026-06-29): Two distinct drift scenarios exist — handle BOTH:
Scenario A — Origin ahead (upstream has new commits): Dev installs can accumulate local commits that diverge from origin, causing git pull to falsely report "Already up to date." Before declaring up-to-date: (1) git fetch origin, (2) git log --oneline HEAD..origin/main — any output = upstream ahead, (3) git diff --stat origin/main — any diff = content drift regardless of commit history, (4) cross-check SKILL.md version: field against git log origin/main --oneline -1 — frontmatter can lag commit messages. See Gotchas for conflict resolution when local modifications contradict upstream direction.
Scenario B — Local drift (working tree dirty, origin NOT ahead): When git log HEAD..origin/main is EMPTY but git diff --stat origin/main shows changes, OR when git status lists untracked files, the local working tree has accumulated modifications that origin doesn't have. This commonly happens when: session journals are written into references/, SKILL.md gets edited locally without committing, or new support files are added but not pushed. Diagnostic: git status --short — if output is non-empty with origin at same commit, you have local drift. Response: (1) Separate operational artifacts (session journals in references/) from skill content changes (SKILL.md edits, new reference docs). (2) Session journals should be moved to commons/data/ocas-forge/journals/ — they do NOT belong in the skill repo. (3) Skill content changes should be committed and pushed, or stashed if experimental. (4) NEVER git add . blindly — this commits operational logs into the skill's git history. Confirmed 2026-06-29: 100+ session journals accumulated in references/ over 7 days, causing git diff --stat to show 100+ untracked files with origin at same commit.
Skill consolidation
forge.consolidate merges an orphan or duplicate skill into its natural parent.
See references/builder_workflows.md for the full workflow.
Core rule: fold merged content into the parent's existing section structure.
Do NOT wrap in ## Integrated: sections.
GitHub repo creation
Before creating any GitHub repo, verify the skill is OCAS-authored. Seereferences/github_repo_guardrails.md for the full guardrail checklist.
Skill library search APIs
When Phase 1.5 triggers skill library research, use these APIs to understand approaches and patterns — not to copy verbatim.
- SkillsMP —
sk_liv...370Ikey, https://skillsmp.com/docs/api - AgentSkill.sh —
agentskillCLI, https://agentskill.sh - LobeHub —
lobehubCLI, https://lobehub.com/cli - Skills.sh — https://www.skills.sh/docs/api
- OpenClaw —
clawhubCLI, https://docs.openclaw.ai/clawhub/cli - GitHub OCAS repos —
gh search repos "ocas-* user:indigokarasu" --json fullName,description,url
Output of library search: For each relevant skill found, note: name, description, how it works (architecture), what patterns it uses, and what the new skill can learn from it. Synthesize — don't clone.
When asked to audit sync state of all OCAS skills, or when running a scheduled
sync check, use the workflow in references/sync_audit_procedure.md.
Skill audit
forge.audit audits one or more existing OCAS skills for architecture compliance,
applies fixes, and syncs to GitHub.
Platform notes
Forge uses the memory tool lightly — only for build state during multi-step builds.
Support File Map
| File | When to read |
|---|---|
references/design_pipeline.md |
Before forge.build — the mandatory 8-phase pipeline |
references/init_procedure.md |
On first invocation of any Forge command |
references/sync_audit_procedure.md |
Before forge.sync-audit |
references/package_patterns.md |
Before structuring a new skill package |
references/authoring_rules.md |
Before writing or editing any skill SKILL.md |
references/builder_workflows.md |
Before forge.verify-update, forge.consolidate, forge.sync, or forge.audit |
references/github_repo_guardrails.md |
Before creating any GitHub repo or PR |
references/synthesis-methodology.md |
When synthesizing a new skill from multiple source skills |
references/schemas.md |
Before creating or validating data structures |
references/storage-layout.md |
When debugging data path issues or managing disk |
references/naming-and-authorship.md |
Before naming, renaming, or setting author on any skill |
references/journal-scan-cron-guide.md |
Before running forge:journal-scan — cron mode procedures |
references/frontmatter-editing-pitfalls.md |
Before editing any skill frontmatter |
references/dispatch-pipeline-guide.md |
Multi-skill dispatch workflow (Forge+Mentor+Praxis) — genuine vs second-wave decision procedure, 7 eval gap patterns, cross-directory relpath false positive, journal writing standards, third-wave mitigation, post-dispatch cleanup, phantom file prevention. CONSOLIDATES 60+ dispatch patterns. Load BEFORE running any dispatch pipeline. |
references/session-20260630-dispatch-1035Z-forge.md |
Dispatch 2026-06-30T10:35Z: Mixed genuine no-op, dict double-assignment typo (state["k1"] =["k2"] = val → SyntaxError). Eval file: 48,940. |
references/stale-proposal-backlog.md |
Before scanning proposals — handling stale unprocessed proposals |
references/journal-file-path-construction.md |
Before writing any journal — correct path pattern with date subdirectory, recovery from misplaced files |
references/session-20260624-forge-update.md |
Session-specific: forge.update — untracked files caused false "drift" signal, diagnostic sequence |
references/session-20260624-dispatch-36.md |
Session-specific: dispatch #36 — routine multi-skill dispatch, third-wave mitigation |
references/session-20260625-dispatch-126-forge.md |
Dispatch #126 (2026-06-25): Email triage + multi-skill. Fork-vs-local mismatch: PR fix already in fork from prior dispatch — wasted re-fix before checking git log fork/<branch>. |
references/session-20260626-dispatch-135-forge.md |
Dispatch ~#133 (2026-06-25): Multi-skill clean scan + email second-wave. 0 unprocessed proposals (11 total). All 4 new journals already in eval file. State file age gap (50 min) confirms is_new: false authoritative. |
references/session-20260626-dispatch-021-forge.md |
Dispatch #21 (2026-06-26): Multi-skill clean scan + email wave 21. Heredoc leak incident (commands after JSON in heredoc body). Phantom file cleanup. Third-wave mitigation applied. |
references/session-20260626-dispatch-139-forge.md |
Dispatch #139 (2026-06-26): Multi-skill clean scan + email second-wave. 0 unprocessed proposals (11 total). Third-wave mitigation applied. |
references/session-20260626-dispatch-140-forge.md |
Dispatch #140 (2026-06-26): Second-wave self-referential pattern confirmed. Dispatcher detected prior wave's own journals as "new_files". All pipelines clean. No escalations. |
references/session-20260626-dispatch-027-forge.md |
Dispatch #142 (2026-06-26): Second-wave with eval file gap. Prior-wave journal missing from eval file despite last_ingest_run coverage. Third-wave mitigation scope must include all 7 relevant journals. grep -c shell parsing pitfall. |
references/session-20260626-dispatch-141-forge.md |
Dispatch #141 (2026-06-26): Cron-output journal detected as new file. Praxis-cron journal NOT in eval file — must add manually. Wikipedia email (Francis Ralph Rambo accepted). |
references/session-20260626-dispatch-146-forge.md |
Dispatch #146 (2026-06-26): Partial cycle eval gap between sibling pipelines. Mentor-light in eval but praxis-cron from same cycle missing. Confirms universal per-journal grep rule — never infer sibling coverage. |
references/session-20260626-dispatch-144-forge.md |
Dispatch #144 (2026-06-26): Second-wave with dispatch-output eval gap. Prior wave's forge-scan and praxis-dispatch journals missing from eval file despite mentor-light from same wave being present. Consolidated eval gap pattern table (all 3 sub-variants). |
references/session-20260626-dispatch-cron-execute-code-blocked.md |
Dispatch (2026-06-26): execute_code blocked in cron mode — workaround via terminal() heredoc Python. Steady-state multi-skill dispatch. |
references/phantom-file-cleanup.md |
After writing journals via terminal() — empty timestamps, double timestamps, malformed filenames |
references/session-20260626-dispatch-148-forge.md |
Dispatch #148 (2026-06-26T08:00Z): Genuine new dispatch with eval gap backfill. All 4 new_files NOT in eval file → full pipeline execution required. Key pattern: distinguishing genuine dispatch from second-wave via per-journal grep + eval file staleness check. |
references/session-20260626-dispatch-150-forge.md |
Dispatch #150 (2026-06-26T08:23Z): Genuine dispatch, 5 eval gaps backfilled. Prior wave's dispatch journal self-identified as "second-wave" but its journals were NOT in eval file — self-identification is not authoritative. |
references/session-20260629-dispatch-0245Z-forge.md |
Dispatch 2026-06-29T02:45Z: Genuine dispatch + second-wave hybrid with stale cron gap. 4 of 5 second-wave files in eval, but 1 stale cron journal (mentor-light-084028Z) missed by all prior waves. Key learning: second-wave = add gaps + advance state, never write new dispatch-output journals (creates third wave). |
references/session-20260629-dispatch-0440Z-forge.md |
Dispatch 2026-06-29T04:40Z: Genuine dispatch. Dispatcher new_file vs heartbeat output divergence — mentor-light-043547Z (dispatcher) ≠ mentor-light-044551Z (heartbeat). Both need eval registration. Forge clean, Mentor correction 8→22. |
references/session-20260629-dispatch-0513Z-forge.md |
Dispatch 2026-06-29T05:13Z: Genuine full pipeline. 2 eval gaps (rally weekend research + praxis-cron). Classification-first, dual eval check, prior-wave skip, new_file/heartbeat divergence all confirmed working. Mentor correction 8→22 (confirmation #51+). Eval file: 48,276. Steady-state confirmation #56+. |
references/session-20260626-dispatch-154-forge.md |
Dispatch #154 (2026-06-26T08:55Z): Cross-skill journal gap — ocas-rally journal missed by dispatcher detection. Eval file path consistency (absolute vs relative). Broader post-ingest gap scan pattern. |
references/session-20260626-dispatch-155-forge.md |
Dispatch #155 (2026-06-26T09:06Z): Post-dispatch cron journal gap — cron writes between eval backfill and third-wave mitigation. Complete 7-pattern eval gap catalog. Post-dispatch cleanup rule. |
references/session-20260626-dispatch-153-forge.md |
Dispatch #153 (2026-06-26T08:50Z): Genuine dispatch with "before last_ingest_run" eval gap. mentor-light-084534Z (08:45:34) was 90 seconds BEFORE last_ingest_run (08:46:42) but NOT in eval file. Key learning: last_ingest_run is an operation boundary, not a coverage boundary — always grep, never assume prior-timestamp journals are covered. |
references/session-20260626-dispatch-151-forge.md |
Dispatch #151 (2026-06-26T08:35Z): Genuine dispatch with tight eval gap (2-4 min). last_ingest_run was 08:28:23 but cron journals written at 08:30-08:32 were NOT in eval file. Key learning: eval gap is measured in WAVES not minutes — always grep, never infer from timestamp proximity. |
references/session-20260626-dispatch-156-forge.md |
Dispatch #156 (2026-06-26T09:27Z): Genuine dispatch with post-dispatch cron gap. 3 prior-wave journals + 1 cron gap backfilled. Verification pitfall: $(date) micro-differences between journal filename and eval entry timestamp cause false-negative grep. Use partial timestamp matching for verification. |
references/session-20260626-dispatch-161-state-file-read-discrepancy.md |
Dispatch ~#161 (2026-06-26T10:51Z): read_file returns stale/wrong state file content vs Python json.load(). Critical pitfall for dispatch classification. |
references/session-20260626-dispatch-160-forge.md |
Dispatch #160 (2026-06-26T10:21Z): Genuine dispatch + massive legacy backfill (865 files). Double-Z timestamp bug in ingest_state.json. Post-dispatch cleanup one-time backfill pattern. |
references/interactive-menu.md |
When invoked interactively via / command — two-level menu layout, response parsing, platform adaptation |
references/session-20260626-dispatch-158-forge.md |
Dispatch #158 (2026-06-26T09:45Z): Genuine dispatch, 3 cron-written journals (09:40-09:43) not in eval → full pipeline execution. All 3 pipelines clean. 3 eval gaps backfilled + 3 third-wave mitigation entries. Eval file: 10,336 entries. Confirmation #56+ of steady-state pattern. |
references/session-20260626-dispatch-165-forge.md |
Dispatch #165 (2026-06-26T13:13Z): Genuine no-op mixed dispatch (journals + email), state counter drift fix (journals_evaluated_count sync). Steady-state confirmed. |
references/session-20260627-dispatch-1240-forge.md |
Dispatch ~#1240 (2026-06-27T12:40Z): Mixed genuine no-op. 4/5 journals in eval, 1 eval gap (praxis decay-check). All content routine. No pipeline skills loaded. Eval file: 39,905 entries. |
references/session-20260627-dispatch-1424Z-forge.md |
Dispatch ~#1424 (2026-06-27T14:24Z): Genuine no-op. 2 routine mentor-light journals not in eval + 2 eval gaps from post-ingest cron. Skipped all pipeline skills. 4 eval gaps registered. Eval file: 40,560 entries. |
references/session-20260626-dispatch-wave-second-wave-path-fix.md |
Second-wave no-op + eval path base fix — os.path.relpath(fpath, ".") vs relpath(fpath, "commons/journals") causes mismatched eval entries on every cleanup. Confirmed 2026-06-26. |
references/session-20260628-dispatch-0835Z-forge.md |
Dispatch 2026-06-28T08:35Z: Second-wave where agent incorrectly wrote forge-scan/mentor-light/praxis-dispatch journals before classification. Classification-first ordering pitfall — classify BEFORE writing any journals. Corrected by removing pipeline journals, writing only dispatch-wave. |
references/session-20260628-dispatch-035335Z-forge.md |
Dispatch 2026-06-28T03:53Z: Mixed genuine no-op (journals + email). is_new: true promotional email (Verily Me survey) ≠ actionable. GitGuardian on indigo config repo = known pattern (auth tokens in operational config). Genuine-no-op shortcut applied. |
references/session-20260627-dispatch-233646Z-forge.md |
Dispatch @23:36Z (2026-06-27T23:36Z): Second-wave with explicit pipeline prompt. Wrote forge-scan-*.json journals incorrectly — should write dispatch-wave-*.json only on second-wave. |
references/session-20260628-prior-wave-dispatch-wave-skip.md |
Prior-wave dispatch-wave skip rule — timestamp < detected_at → skip entirely |
references/session-20260629-skill-audit-consolidation.md |
2026-06-29 skill audit — forge_audit_skills.py is a stub, manual audit procedure, ocas-critique → ocas-skilllab consolidation |
references/session-20260629-forge-update-local-drift.md |
2026-06-29 forge.update — Local drift pattern (origin at same commit, working tree dirty). ~ expansion pitfall in terminal(). Session journals in references/ vs skill content. |
references/session-20260630-dispatch-0642Z-forge.md |
Dispatch 2026-06-30T06:42Z: Multi-skill dispatch, 20 journals ingested. Dispatch-wave mixed_genuine_no_op false positive — Praxis ingest incorrectly recorded it as an event, required manual cleanup. New rule: dispatch-wave outcomes containing no_op are routine orchestration, not behavioral signals. Eval file: 48,895. Steady-state. |
references/session-20260630-dispatch-1125Z-forge.md |
Dispatch 2026-06-30T11:25Z: Pure eval-registration dispatch. All new_files already in praxis eval or prior-wave artifacts. 0 pipelines loaded. Shell heredoc vs inline Python JSON writing pitfall (6 failures). New pattern: pure eval-registration shortcut. Eval file: 48,947. Dispatch eval: +2. |