Skip to content

feat: adapter-first enumeration + consistent issue filing - #43

Merged
tato123 merged 6 commits into
mainfrom
feat/adapter-first-enumeration
Apr 21, 2026
Merged

tato123 merged 6 commits into
mainfrom
feat/adapter-first-enumeration

Conversation

@tato123

@tato123 tato123 commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Two related workflow fixes for amos projects:

  1. Adapter-first enumeration — GitHub issues without a local plan file were previously invisible to amos milestones / next / blocked / graph. Every command now enumerates from the adapter (GitHub), and plan files become optional AI-notes overlays.
  2. Consistent issue filing — new amos-file skill + amos issue-create subcommand. From short natural-language intent, drafts a well-shaped issue following the project's template (docs/issue-template.md or .github/ISSUE_TEMPLATE/*.md), infers milestone and labels with an AskUserQuestion fallback when confidence is low, extracts explicit relationships, and creates the issue atomically with native blockedBy / blocking / parent edges applied.

Also included:

  • amos sync-edges — one-time migration that pushes existing plan-file blocked_by: / blocks: frontmatter up to native GitHub relationships. Idempotent; safe to re-run.
  • amos-next Step 7 now detects every issue the branch addresses (primary + commit-message Closes #N + branch name) so merges auto-close the full set, not just the primary issue.
  • Adapter trait extensions: list_milestones, list_nodes_in_milestone, add_relationship, create_issue (default no-op/error impls — non-GitHub adapters are untouched and forward-compatible).
  • GhAdapter::with_detected_repo — auto-detects owner/name from the scan root's git remote.

Motivation

Pre-change behavior required a local plan/N-slug.md for every issue you wanted amos to see. Two-source-of-truth trap: file an issue in GitHub, it doesn't show up in amos next, no warning. Concretely observed on streamlib: 6 open issues in the focused milestone reported open: 0, hiding the next unit of work.

Filing issues also required hand-authoring the full template every time. That's friction we can remove — the template rarely changes, milestone inference is usually obvious, and the rare ambiguous cases are exactly when AskUserQuestion shines. The skill drafts; the user approves the whole package in one step; the binary creates the issue + applies labels/milestone/relationships atomically.

Design

  • Trait extension (back-compat): four new Adapter methods with empty default impls — list_milestones, list_nodes_in_milestone, add_relationship, create_issue. Non-GitHub adapters are untouched.
  • GhAdapter: implements all four via gh api graphql / gh issue create. Detects owner/name from the scan root's git remote so no new configuration is required.
  • main.rs merges adapter-sourced nodes with parsed local nodes: local wins for AI-facing fields (body, context, labels); the adapter provides state + native edges and contributes virtual nodes for issues that have no local plan.
  • sync-edges: iterates every resolvable local edge, normalizes to a canonical (blocked, blocker) form (so mirror declarations don't push twice), and calls addBlockedBy. "Already exists" responses are treated as success, making the operation idempotent.
  • issue-create: the amos-file skill produces a JSON IssueSpec (title, body, milestone, labels, blocked_by, blocks, sub_issue_of) and pipes it to the binary. Binary does gh issue create then applies native relationships in a single pass. Partial relationship failures are reported to stderr; the issue exists either way.
  • PR auto-link — pure skill change in amos-next. Grep the branch's commits for Closes / Fixes / Resolves #N, combine with the primary issue and branch-name detection, emit one Closes #N per line in the PR body.

Test plan

  • cargo test — 68 passed (11 new: remote URL parsing, adapter-node JSON mapping, trait-default fallbacks, registry routing, empty-title rejection).
  • cargo clippy — no new warnings introduced by this PR.
  • Live smoke against tatolab/streamlib:
    • amos milestones shows accurate counts (Polyglot SDK Realignment fixed: 6 open / 3 done, matching GitHub).
    • amos next in the focused milestone enumerates the 6 unplanned issues that were previously invisible.
    • amos sync-edges --dry-run reports 123 unique edges (140 raw, 17 mirror dedups).
    • amos sync-edges applied all 123; zero failures.
    • Post-migration verification queried GitHub blockedBy for every source issue and diffed against the snapshot — zero missing / zero extra.
  • amos issue-create subcommand: edge cases (empty title, malformed JSON, missing scheme) route cleanly.

Breaking changes

None. Existing plan-file edges are still read and merged. Projects that haven't migrated keep working.

Follow-ups (not in this PR)

  • After downstream projects run sync-edges and verify, delete the plan-file DAG code path.
  • Add batch node-ID lookup to add_relationship (currently ~2 GraphQL calls per edge — acceptable at this scale).
  • Sub-issue (parent/child) support in amos-file once any project uses GitHub's sub-issue feature.

🤖 Generated with Claude Code

tato123 and others added 2 commits April 20, 2026 23:04
Fixes a silent failure mode where GitHub issues filed in a tracked
milestone were invisible to amos because they had no corresponding
local plan file. Milestone counts, `amos next`, `amos blocked`, and
`amos graph` now enumerate from the adapter's source of truth and
merge local plan files as optional overlays.

- Adds `list_milestones`, `list_nodes_in_milestone`, `add_relationship`
  to the `Adapter` trait (default empty impls — non-GitHub adapters
  forward-compat).
- `GhAdapter` implements all three via GraphQL. Reads GitHub's native
  typed relationships (`blockedBy`, `blocking`, `parent`, `subIssues`)
  so the DAG gets authoritative edges, not stale plan-file copies.
- `GhAdapter::with_detected_repo` — detects `owner/name` from the scan
  root's git remote, so a default repo is available for milestone
  enumeration without requiring every reference to be fully-qualified.
- New `amos sync-edges [--dry-run]` subcommand — one-time migration
  that pushes every local `blocked_by` / `blocks` frontmatter edge up
  to GitHub as a native `addBlockedBy` relationship. Idempotent; safe
  to re-run. Canonicalizes mirror declarations (A.blocks:[B] +
  B.blocked_by:[A]) before pushing.
- `main.rs` merges adapter-sourced nodes with parsed local nodes. Local
  nodes win for AI-facing fields (body, context, labels); the adapter
  fills in state + native edges and contributes virtual nodes for
  issues without a plan file.
- Skills: updates `amos` SKILL.md to reflect the new "GitHub is the
  source of truth, plan files are optional AI-notes overlays" model.
  Documents `sync-edges`. Other skills are unchanged — they were
  already adapter-correct.
- 10 new unit tests for the pure helpers (remote URL parsing, JSON-to-
  AdapterNode mapping, trait-default fallbacks, registry routing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Second half of the adapter-first push. The bug fix (PR title) stands on
its own; this commit adds the authoring side — consistent issue filing
and PR close-link coverage — so the workflow loop is symmetric:
`amos-file` creates issues, `amos sync-edges` migrates old projects,
`amos-next` consumes them and auto-closes every addressed issue on PR
merge.

- New `Adapter::create_issue(spec) -> CreatedIssue` trait method (default
  errors). `GhAdapter` implements via `gh issue create`, returning
  the canonical amos name + URL.
- New `amos issue-create --scheme github --spec <path|->` subcommand.
  Reads an `IssueSpec` JSON from stdin or a file (title, body,
  milestone, labels, blocked_by, blocks, sub_issue_of), creates the
  issue, then applies every native relationship in one atomic pass.
  Partial relationship failures are reported in the result but don't
  roll back the creation — the issue exists, the skill can retry the
  edges.
- New `amos-file` skill. Handles the authoring flow: capture intent,
  discover a project template (`docs/issue-template.md` or
  `.github/ISSUE_TEMPLATE/*.md`, falling back to an amos default),
  draft title + body, infer milestone + labels with AskUserQuestion as
  the fallback when confidence is low, extract explicit relationships
  from the user's intent, present the whole draft at an
  AskUserQuestion gate, and hand off to the binary via JSON spec.
  Supersedes the older plan-file-scaffolding `amos-create` skill.
- `amos-next` Step 7 now collects every issue the branch addresses —
  not just the primary — by grepping the branch's commits for
  `Closes/Fixes/Resolves #N` and optionally parsing the branch name,
  so GitHub auto-closes all of them on merge.
- Early-route `IssueCreate` before the local scan so projects with
  legacy plan-file frontmatter can still file new issues without
  having to run `amos migrate` first.
- One new test covering empty-title rejection. Existing test count
  unchanged elsewhere (68 passed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tato123 tato123 changed the title feat(adapter): adapter-first enumeration + native GitHub relationships feat: adapter-first enumeration + consistent issue filing Apr 21, 2026
tato123 and others added 2 commits April 20, 2026 23:31
Adds a mandatory `## AI Agent Notes` section to the default template,
wrapped in HTML markers (`<!-- amos:ai-notes-begin -->` /
`<!-- amos:ai-notes-end -->`) so amos tooling can find and update the
section safely without risking the rest of the body.

Motivates the section explicitly: agent-facing context (exact error
strings, file paths, ruled-out approaches, hidden invariants) that
doesn't belong in the human-readable Description/Context but is
load-bearing for any agent picking the issue up later.

Also spells out the rule for project-specific templates: follow the
project's sections verbatim, but append an AI Agent Notes section if
the template doesn't already include one — the section is the contract
between human-filed issues and agents, and it's the same shape as the
migrated content from existing plan-file bodies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iles

A remote-first project can legitimately have zero local plan files —
every issue, milestone, and relationship lives in GitHub. The previous
check bailed on any command besides Milestones / SyncEdges when no
local blocks were present, which broke `next`, `blocked`, `orphans`,
and `graph` for fully-migrated projects.

Reverse the flag: only commands that genuinely need local state
(`validate`, the default DAG dump) require at least one local block.
Everything else falls through and pulls its nodes from the adapter.

Surfaced while deleting streamlib's entire plan/ directory after
migrating every edge and every AI-notes body to GitHub issues.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tato123 and others added 2 commits April 20, 2026 23:54
Only four reference kinds map to native GitHub relationships
(blocked_by, blocks, sub_issue_of, duplicate). Everything else —
"exposed by", "surfaced by", "follow-up to", "see also", "related to"
— is free-text context with no native equivalent, and calling it out
at all is usually noise the next agent has to mentally filter. If a
reference doesn't affect work order, don't include it.

Rule of thumb spelled out: if a reference doesn't fit the four-row
table, it's probably not a relationship worth calling out. Native
relations are load-bearing for `amos next` / `amos blocked`; soft
refs add cognitive overhead without gating anything.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub exposes three repo-level issue types — Bug, Feature, Task — as
a first-class field distinct from labels. `gh issue create` doesn't
support setting them, so amos now applies the type via the
`updateIssueIssueType` GraphQL mutation right after creation.

- `IssueSpec::issue_type: Option<String>` — case-insensitive match
  against the repo's configured types. Omit to leave unset.
- `GhAdapter::create_issue` looks up the repo's types on demand (one
  GraphQL call) and resolves the name to an ID before firing the
  mutation.
- main.rs parses `issue_type` from the spec JSON.
- The `amos-file` skill now has a Step 4.5 for type inference with
  conventional-commit heuristics (fix→Bug, feat→Feature, everything
  else→Task) and an AskUserQuestion fallback when confidence is low.
- Draft gate + JSON spec shapes updated to include the type field.

Doesn't backfill existing issues — types are a creation-time concern
that's easy to set later per-issue via `gh api graphql` if needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tato123
tato123 merged commit b1c624f into main Apr 21, 2026
6 checks passed
@tato123
tato123 deleted the feat/adapter-first-enumeration branch April 21, 2026 04:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant