Skip to content

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.