Version 0
MortelOS Issue Factory
Issue dossiers, issue storage and lifecycle commands for an autonomous TDD issue loop.
mortelos/issue-factory provides the issue dossiers, issue storage and lifecycle commands that an autonomous TDD issue loop works from.
Use It For
| Area | Package responsibility |
|---|---|
| Issue dossiers | Describe one unit of work: title, problem, scope, acceptance criteria, a unit, feature, e2e and browser test plan, touched surfaces, package decision, priority, dependencies and risk. |
| Validation | Treat a dossier as incomplete without a title, problem, acceptance criteria, at least one test case or a package decision type. |
| Markdown feed | Write dossiers as markdown files with an embedded JSON block, by default in .claude/issues. |
| OS storage | Store dossiers as issue entities in a tenant. State changes, events, links and metrics are recorded as entity updates by the issue-factory actor. |
| Lifecycle | Track issues through drafting, queued, in_progress, blocked, pr_ready, merged and cancelled. |
| Ready queue | Pick the queued issue with the lowest priority value whose dependencies are all merged. |
| Agent skill | Ship a create-issue skill that turns a merged mortelos/* package change into dossiers through issue-factory:create. |
Install
composer require mortelos/issue-factory
Packages resolve from the MortelOS registry. Configure registry access once before installing; see Installation.
Register the issue entity type in each tenant that stores issues. The command does nothing when the type already exists:
php artisan issue-factory:install --tenant=<id|slug>
Commands
php artisan issue-factory:create --input=issue.json --queue
php artisan issue-factory:sync --tenant=<id|slug> --dry-run
php artisan issue-factory:next --tenant=<id|slug> --peek --json
php artisan issue-factory:show <id> --tenant=<id|slug> --json
php artisan issue-factory:finish <id> --tenant=<id|slug> --pr=<pull-request-url>
php artisan issue-factory:finish <id> --tenant=<id|slug> --block --reason="Needs a host decision"
| Command | Behavior |
|---|---|
issue-factory:create |
Reads a JSON dossier from --input (a file, or - for stdin), stamps an id and writes it to the markdown feed as drafting, or queued with --queue. Refuses an incomplete dossier unless --allow-incomplete is passed. Needs no tenant. |
issue-factory:sync |
Ingests the markdown feed into the tenant. Adds only issues the tenant does not hold yet, promotes new drafting dossiers to queued and skips invalid ones. --dry-run reports without writing. |
issue-factory:next |
Shows the next ready issue and claims it as in_progress. --peek shows it without claiming. |
issue-factory:show |
Prints one issue. --json prints the full dossier. |
issue-factory:finish |
--pr moves an in_progress issue to pr_ready and links the pull request. --block with a required --reason moves it to blocked. Transitions the lifecycle does not allow are refused. |
create and sync accept --path to use another feed directory than the configured one.
Configuration
Publish the config, or copy the create-issue skill to .claude/skills/create-issue/SKILL.md in the host:
php artisan vendor:publish --tag=issue-factory-config
php artisan vendor:publish --tag=issue-factory-skills
| Key | Default | Purpose |
|---|---|---|
issue-factory.source |
os |
os or local: which source the container binds for IssueSource. Env: ISSUE_FACTORY_SOURCE. |
issue-factory.local_path |
.claude/issues |
Markdown feed directory, relative to the host base path. Env: ISSUE_FACTORY_LOCAL_PATH. |
issue-factory.entity_type |
issue |
Entity type name used for issues in the tenant. |
Resolve Mortelos\IssueFactory\Contracts\IssueSource to read and write issues from host code. With source set to os it uses the tenant entity store when a tenant is initialised and falls back to the markdown feed otherwise. The artisan commands do not use this binding: create always writes the feed and the tenant commands always use the entity store.
Outlets
An outlet is a place where you extend mortelos/issue-factory from your app without changing the package. The table lists the outlets in its resources/mortelos/outlets.json as of version 0.1.3; read Outlets for how each kind works and what to do when none fits.
php artisan mortelos:outlets:list issue-factory
| Kind | Name | What it is for |
|---|---|---|
| contract | Mortelos\IssueFactory\Contracts\IssueSource |
Where the issues live (tenant entities or a markdown feed). Only applies to code that resolves IssueSource from the container: the artisan commands (sync, finish, show, next, create) build their own source and ignore this binding, so binding your own IssueSource does not change what they do. Default: OsEntityIssueSource. |
| config | issue-factory |
Source (os or local), markdown folder, entity type, maximum attempts, stop point and source marker of the issue loop. Publish with php artisan vendor:publish --tag=issue-factory-config. |
Boundaries
Use this package for the dossier format, issue storage, lifecycle states and the commands around them. It does not run the build loop, write code, or open or merge pull requests. The host owns the agent loop that claims issues with issue-factory:next and reports back with issue-factory:finish. No command sets merged or cancelled: the host records those, for example through IssueSource::updateState(), and an issue with dependencies only becomes ready once they are merged. Tenants and the entity store come from mortelos/framework.