intentional-core 0.1.1

Core model and release planning for intentional
Documentation

relationships: implements: intent-driven-polyglot-release

intentional

intentional is an intent-driven, polyglot release and versioning CLI. Pending intent files say what the next version should be, Git tags say what has been released, and manifests are format-preserving projections of that state.

The tool supports npm, Cargo, Pub, PEP 621 Python projects, MSBuild projects, Go modules, and arbitrary JSON, TOML, and YAML version fields. It never publishes packages, commits, pushes, or opens pull requests. tag is its only Git-writing command, and it creates lightweight tags without a v prefix.

Install

With Homebrew:

brew tap wyrd-company/tools
brew install intentional

With Cargo:

cargo install intentional-cli --locked

Build

task build
cargo run --bin intentional -- --help

The minimum supported Rust version is 1.82. The library crate is intentional-core; the binary package is intentional-cli and installs the intentional executable.

Initialize a repository

intentional init

init scans for package.json, package-bearing Cargo.toml, pubspec.yaml, *.csproj, pyproject.toml, and go.mod files. It writes a logical package inventory to .intentional/config.yml and creates .intentional/intents/.

A package with npm and Pub projections at one shared version can be configured like this:

$schema: https://intentional.foo/schemas/config.yml
settings:
  global-tag: false
  internal-dependency-bump: patch
packages:
  sample-runtime:
    path: packages/runtime
    projections:
      - adapter: npm
        file: package.json
        mode: committed
      - adapter: pub
        file: pubspec.yaml
        mode: committed
    tag: "{id}@{version}"
  sample-application:
    path: packages/application
    projections:
      - adapter: npm
        file: package.json
        mode: committed
    depends-on: [sample-runtime]

Projection modes are:

  • committed: apply writes the release version.
  • injected: stamp writes the computed build version.
  • none: no manifest version is written; Go uses this mode.

Generic json, toml, and yaml projections also require a pointer, such as /metadata/version.

Author and inspect intents

intentional add \
  --package sample-runtime:minor \
  --package sample-application:patch \
  --message "Add a user-visible capability."

intentional status
intentional check

Without flags, add prompts for a package, bump, and changelog message. It creates a memorable-slug Markdown file such as:

---
sample-runtime: minor
---

Add a user-visible capability.

status lists pending intents, tag-derived current versions, computed next versions, and manifest drift. check validates the config and intent package references and confirms that plan generation is deterministic.

Before 1.0.0, bumps express compatibility significance uniformly across ecosystems: major advances 0.x.y to 0.(x+1).0, while both minor and patch advance it to 0.x.(y+1). Reaching 1.0.0 is always an explicit human act: deliberately tag 1.0.0, after which the next release computes from that tag using strict SemVer rules.

Plan and apply a final release

intentional plan > release-plan.json
intentional apply

# The surrounding harness owns commit choreography.
git add -A
git commit -m "chore: apply release"

intentional tag

plan writes compact canonical JSON to standard output. Its object keys are sorted, and its digest is a SHA-256 seal over the canonical payload excluding the seal itself. The plan contains old and new versions, contributing intent ids, tags, dependency-ordered publication order, and rendered release notes.

apply updates committed projections, rewrites internal dependency ranges, updates each logical package's CHANGELOG.md, and deletes consumed intent files. It changes only the working tree. tag then creates the per-package tags, plus a plain global SemVer tag when settings.global-tag is enabled.

Stamp build versions

For an injected projection, stamp the intent-derived version without touching changelogs or intents:

intentional stamp
intentional stamp --prerelease alpha

The prerelease form composes the next intent version with first-parent commit height since the latest matching package tag, for example 1.3.0-alpha.5.

Channel releases

Channel state is derived entirely from existing tags:

intentional plan --channel beta > release-plan.json
intentional apply --channel beta
git add -A
git commit -m "chore: apply beta release"
intentional tag --channel beta

The first release is X.Y.Z-beta.1; the next iteration is the highest matching channel tag plus one. Channel applies retain intents. A later channel-less apply removes prerelease changelog sections for that version and writes the consolidated final section.

Dry runs

Every mutating command supports --dry-run:

intentional init --dry-run
intentional add --package sample-runtime:patch --message "Correct a defect." --dry-run
intentional apply --dry-run
intentional stamp --prerelease alpha --dry-run
intentional tag --dry-run

Dry runs print the same operation list as a real invocation and make no filesystem or Git changes.

GitHub Action

The plumbing action downloads a released Linux binary and runs one command. Pin the action to a plain SemVer tag because intentional tags do not use a v prefix. This example validates the repository, exposes the canonical plan as an output, and records whether that plan contains any changed packages:

jobs:
  release-intent:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Validate release intent
        uses: wyrd-company/intentional@0.1.1

      - name: Build release plan
        id: release-plan
        uses: wyrd-company/intentional@0.1.1
        with:
          command: plan

      - name: Save changed release plan
        if: steps.release-plan.outputs.changed == 'true'
        env:
          PLAN_JSON: ${{ steps.release-plan.outputs.plan }}
        run: printf '%s\n' "$PLAN_JSON" > release-plan.json

The action also accepts status, stamp, apply, and tag. channel applies to plan, apply, and tag; prerelease applies to stamp; and dry-run applies to the mutating commands.

Release pipeline

A release is prepared with intentional apply, committed, tagged with intentional tag, and sent to GitHub by pushing the plain SemVer tag. The tag-triggered release workflow builds platform archives, creates the GitHub Release, publishes intentional-core followed by intentional-cli to crates.io, updates the stable major action tag after 1.0, and publishes the intentional formula to the wyrd-company/tools Homebrew tap.

Development checks

task fmt-check
task lint
task test
task ci