# Artifact lifecycle example

> End-to-end recipe: signal → task with led-to/addresses edges, status transitions, brief output, and journal linkage—mirroring test/scenario.e2e and skill-regression flows.

- Repository: superdesigndev/loopany
- GitHub: https://github.com/superdesigndev/loopany
- Human docs: https://grok-wiki.com/public/docs/superdesigndev-loopany-97bd9ab97ae8
- Complete Markdown: https://grok-wiki.com/public/docs/superdesigndev-loopany-97bd9ab97ae8/llms-full.txt

## Source Files

- `test/scenario.e2e.test.ts`
- `test/skill-regression.sh`
- `skills/loopany-core/kinds/signal.md`
- `skills/loopany-core/kinds/task.md`
- `skills/loopany-core/conventions/relations.md`
- `src/commands/artifact-status.ts`
- `src/core/artifact-store.ts`

---

---
title: "Artifact lifecycle example"
description: "End-to-end recipe: signal → task with led-to/addresses edges, status transitions, brief output, and journal linkage—mirroring test/scenario.e2e and skill-regression flows."
---

The canonical end-to-end path is exercised by `test/scenario.e2e.test.ts`: record a `signal`, create a `person` and `task`, wire `led-to` and `mentions` edges, pick up work via `followups`, transition the task through `running` → `in_review` → `done` with a `## Outcome`, then verify graph queries. Every non-`journal` create also appends a wiki-link into today's auto-managed journal under `artifacts/journal/<YYYY>/<YYYY-MM-DD>.md`.

## Prerequisites

| Requirement | Notes |
|---|---|
| Workspace | `loopany init` with `$LOOPANY_HOME` set (tests use an isolated temp dir) |
| CLI | `bun run src/cli.ts` or a linked `loopany` binary |
| Kinds | Bundled under `$LOOPANY_HOME/kinds/` after init (`signal`, `task`, `person`, `brief`, `journal`, …) |

<Note>
v0.2 IDs are globally unique slugs (no kind prefix). Title-derived slugs are the default (`Follow up with Alice` → `follow-up-with-alice`); explicit slugs use `--slug` (required for `person`).
</Note>

## Canonical scenario: signal → task → done

This mirrors the Alice contract follow-up in `test/scenario.e2e.test.ts`.

<Steps>
<Step title="Initialize workspace">

```bash
export LOOPANY_HOME=~/loopany   # or a temp path for experiments
loopany init
```

</Step>

<Step title="Record the inbound signal">

```bash
loopany artifact create \
  --kind signal \
  --title "User wants to follow up with Alice about contract"
```

Stdout is JSON with `id`, `kind`, and `path`. The store stamps `status: open` (signal initial state) and appends `[[<id>]]` to today's journal `## Activity` section.

</Step>

<Step title="Create the person entity">

```bash
loopany artifact create \
  --kind person \
  --slug alice-chen \
  --name "Alice Chen" \
  --aliases "alice,a.chen"
```

File lands at `artifacts/people/alice-chen.md`. The slug is the durable ID for `[[alice-chen]]` citations.

</Step>

<Step title="Create the task with scheduling and mentions">

```bash
loopany artifact create \
  --kind task \
  --title "Follow up with Alice on contract" \
  --status todo \
  --priority high \
  --check-at 2020-01-01 \
  --mentions alice-chen
```

`checkAt` is indexed for `loopany followups`. In the e2e test the date is intentionally in the past so `--due today` returns the task immediately.

</Step>

<Step title="Wire reference edges">

Weak causal link (signal produced the task):

```bash
loopany refs add --from <signal-id> --to <task-id> --relation led-to
```

Stakeholder mention (task talks about the person):

```bash
loopany refs add --from <task-id> --to alice-chen --relation mentions
```

`mentions` can also be satisfied by frontmatter `--mentions` or body `[[alice-chen]]`; all three emit the same semantic edge (implicit edges from frontmatter/body vs persisted edges from `refs add`).

</Step>

<Step title="Pick up due work">

```bash
loopany followups --due today
```

Returns JSON metadata for artifacts whose `checkAt` is on or before the cutoff. Terminal statuses (`done`, `cancelled`, `failed` for tasks) are excluded unless `--include-done true`.

</Step>

<Step title="Run the task status machine">

```bash
loopany artifact status <task-id> running
loopany artifact status <task-id> in_review
```

Illegal jumps are rejected by the store (e.g. `todo` → `in_review` fails with a transition error).

</Step>

<Step title="Close with Outcome and done">

```bash
loopany artifact append <task-id> \
  --section Outcome \
  --content "Alice signed today; contract effective 2026-04-29."

loopany artifact status <task-id> done --reason signed
```

The kind playbook requires `## Outcome` before `done` or `failed`; the CLI does not block `done` without that section today—agents and capture skills treat missing Outcomes as a quality failure. `--reason` updates frontmatter only; it does not append a body section.

</Step>

<Step title="Verify end state">

```bash
loopany artifact get <task-id> --format json
loopany refs <signal-id>
loopany refs alice-chen --direction in
loopany artifact list --kind task --status done
```

Expect `frontmatter.status: done`, body containing `## Outcome`, outbound `led-to` from the signal, and inbound `mentions` on the person.

</Step>
</Steps>

### Task and signal status machines

```mermaid
stateDiagram-v2
  direction LR
  state "signal" as sig {
    [*] --> open
    open --> addressed
    open --> dismissed
    addressed --> open
    dismissed --> open
  }
  state "task" as tsk {
    [*] --> todo
    todo --> running
    todo --> done
    todo --> cancelled
    running --> in_review
    running --> done
    running --> failed
    running --> cancelled
    in_review --> done
    in_review --> failed
    in_review --> cancelled
  }
```

## Relation verbs in this flow

| Verb | Direction in this recipe | Meaning |
|---|---|---|
| `led-to` | `signal` → `task` | Weak causal: the observation eventually produced the work item |
| `mentions` | `task` → `person` | Soft reference to an entity involved in the work |
| `addresses` | `task` → `signal` | Strong responsibility: the task resolves the observation |

<Warning>
Do not write inverse edges (`task` → `signal` with `led-to`). Query `--direction in` on the signal instead.
</Warning>

### Closing the signal with `addresses`

After the task ships, mark the signal `addressed` and emit the canonical `addresses` edge in one call:

```bash
loopany artifact status <signal-id> addressed --addressed-by <task-id>
```

`artifact-status.ts` appends `<task-id> addresses <signal-id>` to `references.jsonl` and flips `status` atomically. Transitioning to `addressed` without `--addressed-by` errors. This pattern is covered in `test/cli.e2e.test.ts` and is what `test/skill-regression.sh` scenario 9 expects when upgrading a recurring signal to a task.

`led-to` during intake plus `addresses` on close is the full pair: causality while open, responsibility when finished.

## Journal linkage (automatic)

On every `artifact create` except `journal`, `ArtifactStore` calls `appendToTodayJournal`:

- **Path:** `artifacts/journal/<YYYY>/<YYYY-MM-DD>.md` (`slugLayout: year`, id = date string)
- **Section:** `## Activity` (or `## Backfilled` when `_backfilled: true`)
- **Line format:** `HH:MM [[slug]] — title` (time omitted when unavailable)

Manual `loopany artifact create --kind journal` is rejected at the CLI; the store is the sole writer of journal files.

Each journal wiki-link also yields an implicit `mentions` edge from the journal id to the new artifact. When debugging graph queries, filter `implicit: true` edges if you only care about explicit `refs add` lines.

**Read today's index two ways:**

1. Open the journal markdown file and scan `## Activity`.
2. `loopany refs <YYYY-MM-DD> --direction out` (same set via graph).

For user-facing narrative, create a `brief` (see below)—not a hand-edited journal.

## Extension: brief output after completion

A `brief` is the agent's point-in-time summary back to the user (`skills/loopany-core/kinds/brief.md`). It has no status machine; cite sources so the summary is drillable.

```bash
loopany artifact create \
  --kind brief \
  --title "Morning briefing" \
  --for-date 2026-06-05 \
  --mentions "<task-id>,alice-chen" \
  --content "$(cat <<'EOF'
## What's due today
## What changed since last briefing
- [[<task-id>]] closed: Alice signed; contract effective 2026-04-29.
## Open threads
## Suggested next moves
EOF
)"
```

Persist lineage edges:

```bash
loopany refs add --from <task-id> --to <brief-id> --relation led-to
loopany refs add --from <brief-id> --to <task-id> --relation cites
```

The brief auto-links into the same day's journal like any other kind. To replace a briefing, create a new brief and `supersedes` the old—never rewrite cited briefs in place.

## Skill-regression cross-check

`test/skill-regression.sh` runs Claude with loopany skills installed and asserts workspace shape:

| Scenario | Behavior checked |
|---|---|
| 1 | Natural-language signal creation |
| 2 | Task creation + flip to `running` |
| 9 | Signal upgraded to task; signal status `addressed` |
| 5 | Shipped PR captured as `task` with Outcome-quality work |

Run locally (requires `claude` CLI and API key):

```bash
./test/skill-regression.sh --dry-run   # inspect prompts only
./test/skill-regression.sh 9           # signal → task upgrade only
```

## End-to-end sequence

```mermaid
sequenceDiagram
  participant User
  participant CLI as loopany CLI
  participant Store as ArtifactStore
  participant Journal as journal YYYY-MM-DD
  participant Refs as references.jsonl

  User->>CLI: artifact create signal
  CLI->>Store: create(signal)
  Store->>Journal: append Activity [[signal-id]]
  User->>CLI: artifact create person / task
  Store->>Journal: append Activity lines
  User->>CLI: refs add led-to / mentions
  CLI->>Refs: append edges
  User->>CLI: followups --due today
  User->>CLI: artifact status running / in_review
  User->>CLI: artifact append Outcome
  User->>CLI: artifact status done
  User->>CLI: artifact status signal addressed --addressed-by task
  CLI->>Refs: task addresses signal
  opt Brief
    User->>CLI: artifact create brief + cites/led-to
    Store->>Journal: append [[brief-id]]
  end
```

## Verification commands

| Check | Command |
|---|---|
| E2E scenario | `LOOPANY_HOME=$(mktemp -d) bun test test/scenario.e2e.test.ts` |
| Addressed edge | `bun test test/cli.e2e.test.ts -t "flips signal to addressed"` |
| Followups filter | `bun test test/cli.e2e.test.ts -t "loopany followups"` |
| Full suite | `bun run test` |

<Check>
A healthy lifecycle leaves: (1) markdown files under `artifacts/signals/`, `artifacts/tasks/`, `artifacts/people/`; (2) persisted edges in `references.jsonl`; (3) today's journal with wiki-linked Activity lines; (4) terminal task with `## Outcome` in the body.
</Check>

## Common failures

| Symptom | Cause | Fix |
|---|---|---|
| `Illegal transition` | Status jump not in kind machine | Follow `todo` → `running` → `in_review` → `done` for tasks |
| `addressed-by` error | `addressed` without responsible artifact | Pass `--addressed-by <task-id>` |
| Signal not in followups | `followups` only reads `checkAt` | Tasks use `--check-at`; signals have no `checkAt` field |
| Extra graph edges | Auto-journal `mentions` | Filter implicit edges in JSON output |
| `Cannot create journal` | Manual journal create | Create any other kind; journal is auto-managed |

## Related pages

<CardGroup>
<Card title="Quickstart" href="/quickstart">
First session: init, mission, task, one reference edge, doctor.
</Card>
<Card title="Reference graph" href="/reference-graph">
Relation verbs, implicit mentions, refs/trace queries.
</Card>
<Card title="Artifact commands" href="/artifact-commands">
create, append, status, set, and Outcome conventions.
</Card>
<Card title="Capture workflow" href="/capture-workflow">
End-of-task capture gate and event→kind routing.
</Card>
<Card title="Self-improvement example" href="/self-improvement-example">
Three done tasks with outcomes → reflect → skill-proposal.
</Card>
<Card title="Build and test" href="/build-and-test">
Unit/e2e tests and skill-regression.sh prerequisites.
</Card>
</CardGroup>
