openreachtech/hora-core/hora-plan
Claude Code and agent skill by openreachtech/hora-core
- community
- ext:[{"type":"plugin","description":"Custom plugin integration"}]
Checking that the SKILL.md file is still in the repository.
Plan one version from its spec. Fixes which version is being built, verifies the spec for holes and contradictions in conversation, and writes the feature-level task list. Runs at the root of the hora repository. Invoked by /hora, or directly as /hora-plan.
Install
npx vskill@latest install openreachtech/hora-core/hora-planSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
hora-plan
The planner. Decide which version is being built, get its spec into a state that can actually be built, and write the list of features to build.
Read ../hora/references/structure.md first — the layout, the invariants and the language rule. `../hora/references/asking.md` fixes how anything here is put to a person, and it is the same file /hora-spec reads.
The three things this skill does
The task list is feature-level, never implementation-level. "Build the attendance feature" is an entry. "Write the RpaFlow model" is a checkpoint inside /hora-build, and this skill does not decide it.
This skill may write into specs/. Only /hora-spec may too
Planning is a conversation with whoever wrote the spec, and asking that person to hand-edit twenty separate holes defeats the point of having it. So this skill may write into specs/, under ../hora/references/structure.md, invariant 1:
Approval is per edit, never blanket. What is protected is that no requirement enters `specs/` without a human having read the exact words first.
Step 2 is a proposal, and it is said as one — "I suggest this edit; it is yours to decide". Where the finding is instead that this skill may have misread the document, that is a check — "I read this as X; is that right?" — settled before any edit is proposed (../hora/references/asking.md). Half of what looks like a hole in a spec is a hole in the reading of it.
Step 3 stays in prose. The edit's exact words have to be read, and an option labelled "approve" is what lets somebody not read them. Everything around it defaults to the question tool.
A finding that needs design work goes to `/hora-spec` instead, at the stage that owns it. The split is by what the fix is, not by how large it looks:
| The finding | Where it is fixed | |
|---|---|---|
a missing annotation, a target that names no repository, a typo, a section number that drifted | here, one edit at a time | |
| a missing use case, a use case the design cannot serve, an operation with no kind or no caller, a scope split nobody has made, a contradiction between two designed things | `/hora-spec`, at the stage ../hora-spec/references/stages.md names |
Why it is not all done here. A use case written into specs/ by the planner is a use case no stage ever walked against a data model or a screen.
Never write into a past version's directory. A fix that belongs to an already-released version goes into the version currently being planned, as a full replacement of that section.
1. Fix the version
A version directory is one under `specs/` whose name is a semver version, and nothing else. specs/skeleton/ holds the blank spec — never planned, never implemented, never counted as unfinished. Any other non-semver directory is skipped, and reported once so nobody assumes it was read.
The target version: among those directories, the lowest one whose .hora/tasks/<version>/ has not been generated or still holds unfinished features. If all are finished, the lowest version that exists under specs/ but not under .hora/tasks/. If there is no such version either, report that every version is complete.
Only the directory name counts. If the version written inside spec.md contradicts it, have a human fix it.
If the target version's `spec.md` is empty or missing, hand the run to `/hora-spec` and stop. Never write the first spec of a version here — writing it without those stages means writing use cases nothing ever walked against a design.
A version whose `.hora/spec/<version>/_stages.md` holds a split handoff not marked consumed is handed over the same way. A hand-written spec satisfies the test above while the moved criteria sit unread; the handoff's presence is as mechanical a test as the emptiness (../hora-spec-horizon/SKILL.md, "Splitting a version under way").
Resolve the diffs first
Sort the version directories in ascending semver order and apply them in turn, each overwriting the last. The lowest version is complete; every one after it is a diff against the version immediately before it.
The key for overwriting is `id`. A section that does not appear in the diff is carried over unchanged.
| What the diff wrote | Result | |
|---|---|---|
| heading and annotations only | annotations are overwritten one by one; the body carries over from the previous version | |
| heading, annotations and body | the whole body is replaced (partial patches of prose are not supported) |
Because of this rule, reviving a section takes three lines.
No target, no depends, no body. Only kicked is overwritten.
Deferring is expressed as "`kicked: yes` in this version, `kicked: no` in the next". kicked: yes carries over through diffs.
`rows` is the one annotation that does not carry over. Read it from the section as this version writes it, never from the resolved document: a version that does not write it runs every row target names, where one that inherited an earlier version's rows would silently skip a row nobody chose to skip.
Files of past versions are never rewritten. Carrying bodies over works precisely because past versions are frozen.
A gap in the versions (1.0.0 → 1.5.0) does not break the chain. Only the versions that exist are applied, in ascending order.
Annex material is not diffed in parts. Prose cannot be patched, so the version that wants to change it places the whole text.
Scanning, digests and the judgment about "a section that disappeared" all happen against the resolved document. Handled per file, every feature would be flagged "the spec changed" on every version bump.
Judge whether the version number is valid
The first version (1.0.0) is not judged. From the second on, the diff in .hora/contracts/ is the primary evidence.
| Difference in the contract | The valid bump | |
|---|---|---|
| none | patch (if nothing was added) | |
| fields or types only added | minor | |
| removed, renamed, retyped, or a required field added | major |
Changes that do not appear in a contract (wording fixes, internal refactors) are patch. Something that does not appear in a contract but is visible to users (a new screen) is minor.
Also detect: skipped versions (1.0.0 → 1.5.0; report only, non-blocking), and versions that go backwards or repeat (blocking).
A version number becomes three directory names and a tag in release.yml, so questions about versioning are `blocking: yes`.
How much may be added to a version
The line is not the kind of change but whether the version has been released. Judge by the tag in the hora repository.
A version is an attribute of the spec, not of the code. app's merge into main comes after every declared repository's merge into main, so app's tag is evidence that all of them have been released.
| State of the version | Treatment | |
|---|---|---|
| not released | additions, changes and deletions are all accepted. The version number does not change | |
| released | leave it alone. Do it in the next version |
An unreleased version has no users, so changing a contract breaks nobody. What happens is rework, not broken compatibility. A spec change or a withdrawn feature just before release is entirely normal, and this must not be closed off.
While unreleased, a migration can be rebuilt with db:refresh, so editing the existing migration directly is fine. Once released, add a new migration that undoes it.
A spec change after a child repository has already landed on main becomes an additional PR to that child's main. The version itself is still unreleased, so it may be accepted.
2. Verify the spec, in conversation
What is read
Reached by a link from `spec.md`, and reached by a link alone — not by name or folder.
A file that is none of `spec.md` / a feature file / a declared Source, and that nothing links to at all, is never read — and raises a question (orphan, blocking: no).
`specs/<version>/request/` is the one directory this does not apply to. /hora-spec reads it and drafts sections from it, and what it produced is in `spec.md` by the time planning starts. Reading it here would extract tasks from a wish list nobody was held to.
Declared under Sources, or a <feature>/spec.md | Reached, but not declared | ||
|---|---|---|---|
| Read for | extraction — id/target/depends, features, contracts | interpretation only | |
| Ever produces a task | yes | never |
A file listed under a `Sources` section acts as a feature file, even if it is not named `spec.md`.
Never invent an id
id is the reference key from .hora/tasks/, and once given it never changes.
| Place | How it is decided | |
|---|---|---|
| the H1 of a feature file | join the path segments relative to `specs/<version>/` with `--`. Deterministic and unique | |
a ## section | somebody states it and it is written. If it is not written, do not infer it | |
a ## with no id | tie that section's content to the H1's `id`. The reference stays stable |
Folder and file names must not contain `--`. A ## section's id joins to its feature's id with a single `-` (attendance--monthly-data-model).
`id` is unique across the whole version. On a collision, ask with blocking: yes.
`id`/`target` may come from the spec's own existing ID scheme instead of being written as annotations. Where the entry point's Document information declares an Annotation source row, <!-- id: -->/<!-- target: --> are not required.
- `id` is then the element's own existing identifier, taken as written
- `target` is looked up from the declared prefix table, mechanically. A prefix the table does not cover is treated as an unstated
target: infer from content and reportinferred-annotation(blocking: no)
The annotations
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingkit/skills/hora-plan/SKILL.md
Popularity
- Repository stars
- 56
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Extension points
pluginCustom plugin integration
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/openreachtech/hora-core/hora-plan)