Skip to content

Releases

devagent 1.0.0

Choose a tag to compare

@mtibbits mtibbits released this 18 Sep 05:45
f8d250e

First tagged release, cut at go-public (#463, #464). Everything in this section
had already shipped SHA-by-SHA to master before the tag existed.

  • The plugin carries a version: plugin.json version: 1.0.0 (#532
    re-take).
    Behavior change for every install from the GitHub marketplace,
    stated here because #532 required it never be claimed as "no change": until
    now claude plugin update devagent@devagent followed master commit by
    commit; from this release it resolves to the version string and only sees an
    update when that string changes, so a merge to master reaches installed
    users at the next release rather than immediately. A marketplace added from
    a local checkout loads it in place and is not pinned. Measured on Claude Code
    2.1.223: claude plugin validate --strict now passes (it was
    documented-red on the missing version), and claude plugin tag --dry-run
    resolves devagent--v1.0.0. tests/test_plugin_versioning.py inverts from
    "no version anywhere" to "semver in plugin.json, none in the marketplace
    entry, matching CHANGELOG section", and tests/plugin-validate.bats wires
    the strict gate plus the tag dry-run. README, the docs-site install page and
    SECURITY.md describe the release policy instead of SHA-tracking.

  • The onboarding site can be built and published (#465).
    scripts/build-docs-site.sh renders the docs-site/ pages to a static
    site with pandoc, straight from the tracked markdown — no rendered copy is
    committed. It rewrites page-to-page links, sends links that leave
    docs-site/ to the forge, and fails the build on a link it cannot classify
    or that resolves to nothing, and refuses a pandoc older than 3.x. A new
    publish docs site workflow runs the builder's tests, builds, and can deploy
    to GitHub Pages by keyless OIDC. Deploy is off until the repository
    variable DOCS_SITE_DEPLOY is set to true, because GitHub Pages is not
    enabled on the repository yet and a deploy against a Pages-disabled repo
    fails; docs/pages-deployment.md has the switch-on steps. New optional test
    prerequisite: pandoc 3.x, for tests/build-docs-site.bats only.

  • The oneshot tier's no-repo-diff boundary is enforced mechanically (#595).
    "An operational action, not a repo change" lived in prose in three documents
    and nothing caught a one-shot that quietly produced commits. The oneshot tier
    has no branch step, so no baseline_sha exists and zero_diff_classify
    answered indeterminate forever. What a branchless tier measures is now
    defined as whether the source tree carries unpublished change — on the
    base branch, no commits beyond default_baseline, no uncommitted paths —
    rather than whether the issue itself produced a diff, which a shared source
    tree cannot attribute. A new scripts/oneshot-zerodiff.sh owns the
    predicate: it calls the shared zero_diff_classify unchanged for the commits
    half, adds a git status --porcelain probe for the dirty half (a dirty-only
    tree classifies as empty), compares the checked-out branch to the base, and
    mints one exit code per verdict. cleanup.sh reads the tier itself and
    refuses before any side effect on violated or indeterminate, directing
    the operator to revise.sh --retier standard; every other tier pays one
    header read and never spawns the checker. A shared tree left on a sibling
    issue's branch is the routine indeterminate, with a one-line remedy; a
    recorded linked worktree is indeterminate with a remedy that names the
    tier. The refusal never asserts authorship.
    echo "<reason>" > <issue-dir>/.devagent-oneshot-ack is an auditable escape
    seam for trees git cannot measure.
    commands/document.md's straggler instruction — which told a oneshot to
    commit and promised a step 12 that tier does not have — is carved out, and
    commands/implement.md's "must produce no repo diff" is reframed to the
    decidable form; both key on the tier name, since the research tier omits
    step 12 too.

  • Untracked new source files enter the analyzer's changed-line scope (#591).
    static_analysis_diff.py scoped from git diff alone, which lists TRACKED
    changes only — a brand-new file that had never been git add-ed produced no
    hunks, so every per-file tool skipped it and step 13 passed vacuously for exactly
    the file with the least review history. A new get_untracked_ranges() enumerates
    untracked, non-ignored candidates with
    git ls-files --others --exclude-standard --full-name -z (read-only — no
    git add, no git add -N, no temp commit) and gives each a whole-file
    LineRange(1, <line count>), so cpplint, codespell, ruff, flake8, bandit, mypy
    and cmake-lint run on it and filter_novel counts every line as changed; markdown
    runs print one artifact-visible progress line,
    Untracked files (whole-file scope): … (stderr under --json, #119), and the
    summary labels now say "changed lines or untracked files". The compile-database
    tools (cppcheck, clang-tidy, iwyu, compiler warnings) and git clang-format
    cannot reach a file the build / index does not know and still report it clean —
    a documented limit. Candidates are limited to the suffixes the run_* filters
    already select on (.cc .c .h .py .cmake CMakeLists.txt) and exclude the
    analyzer's own build_dir / -asan / -ubsan / -tsan dirs and any root-level
    build-* dir — where analyze-sanitizers.sh builds regardless of the configured
    build_dir (#324/#351) — which a target project's .gitignore may not cover.
    Names are decoded as UTF-8 (never the locale's encoding), and a listed candidate
    that cannot be read is named on the same artifact-visible stream instead of
    vanishing. scripts/analyze-shellcheck.sh gets the same treatment for
    *.sh / *.bats / *.bash (both its git diff and its git ls-files run with
    core.quotePath=false, so a non-ASCII name — tracked or untracked — is not
    silently dropped), keyed on untrackedness so a tracked file
    whose only hunks are pure deletions keeps its empty range, with an
    untracked (whole-file scope): header line in its artifact. A --files run
    never widens beyond its pathspecs, .gitignored files stay out, and a
    tracked-only tree's output is byte-identical to before.

  • run-suite.sh runs bats test files in parallel for a project that opts in
    (#593).
    New [project.<name>] key suite_jobs (integer ≥ 1, default 1 =
    serial) passes --jobs N --no-parallelize-within-files to bats; tests inside
    one file still run in order, matching the file-granularity safety audit in
    Issue-593's analysis dir. DEVAGENT_SUITE_JOBS overrides it for one run and
    is scrubbed from both suite children (and unset per test by
    tests/lib/hermetic-env.bash), so a test that invokes the runner cannot
    inherit it. Scrubbed alongside it: BATS_NUMBER_OF_PARALLEL_JOBS and
    BATS_NO_PARALLELIZE_ACROSS_FILES, which bats reads from the environment, so
    an inherited value would make the new bats_jobs: line false in either
    direction; and BATS_PARALLEL_BINARY_NAME, which would otherwise let bats
    reach for a binary the probe below never checked. The value is validated
    before either suite runs; N > 1 first checks for GNU parallel by banner (bats
    1.10.0's own probe is miswired — an absent binary surfaced inside the TAP
    stream as a "truncated" suite) and dies naming the package and the
    suite_jobs = 1 seam. The artifact gains a
    trailing bats_jobs: <N> | (none) line. Carriers: README "Running the test
    suite", tests/README.md "Parallel execution", the config skeleton,
    docs-site/configuration.md, the spec's run-suite section, and the
    core-draft-mr skill's artifact-read note.

  • The rederive prober compares the checkout to its baseline and resolves bare
    basenames (#590).
    scripts/rederive.sh now opens its artifact with a
    ## Checkout vs baseline line — behind N, ahead M against default_baseline
    after a best-effort fetch whose outcome (ok / skipped / FAILED / n/a)
    is stamped on the line. Pre-branch, behind > 0 is a ✗ … STALE CHECKOUT
    falsified premise whose remedy names the merge --ff-only to run (Issue-570
    ran draft through improve three commits behind its base with every file probe
    ✓); on the recorded issue branch (every revision re-runs draft) the same
    numbers print as an ℹ row — expected drift, not a premise. An unconfigured
    or unresolvable base prints an explicit ? behind-count undetermined line,
    never a silent 0; a faulting rev-parse/rev-list/ls-tree dies loud. A
    .devagent-baseline marker is acknowledged by existence in the heading and
    never parsed (only branch.sh reads it). A backticked bare basename or path
    suffix (SKILL.md, capture/capture.sh) is matched against the HEAD tree by
    exact suffix at a / boundary: one hit → ✓ tok → path (resolved …) and the
    resolved path feeds the since-log and the file:line drift check; several →
    a ~ … ambiguous advisory row; none → the same ✗ as before (Issue-570's
    artifact carried six ✗ rows, zero real). Plumbing: upstream_fetch sets
    UPSTREAM_FETCH_STATUS (skipped|ok|failed) and runs its fetch with
    GIT_TERMINAL_PROMPT=0, so git's own credential prompt fails instead of
    hanging an unattended step (ship and mergetoall inherit that; an ssh prompt or
    a black-holed remote is not covered — a fetch timeout is a recorded
    follow-up). The prober measures the issue's recorded worktree when
    use_worktree put the branch there (#571's active_tree_resolve), else
    source_dir. Carriers:
    commands/draft.md, the imPlan template's Preconditions note, core-scope
    question 7, and the commands/branch.md override rules describe the new rows.

  • The checklist writers fail closed (#589). checklist_mark refuses a
    name-less mark of a step number that is absent from the ACTIVE ## Revision
    block but present in an older one — the write used to fall th...

Read more