Capstone

Capstone scaffolds a batteries-included Elixir application and then keeps it upgradable. It is the whole stack, wired together and generated in one go:

capstone = cache(valkey) + authn + postgres + svelixir + tailwind
+ openbao + nodejs + elixir

This is one package, one namespace. It carries both the project generator (mix capstone.new, Capstone.New.*) and the engine that keeps a generated project upgradable for the rest of its life (Capstone.*) — installed either as a global mix archive or as an ordinary dependency of a project it generated, from the same capstone-x.y.z.ez/hex release. Nothing here resolves to a runtime dependency in :prod — everything the engine needs at runtime (Sourceror, TypedStruct, Vex, simple_enum) is vendored under lib/capstone/vendor/ instead of declared in mix.exs, and every declared dependency is only::dev/:test. CredoNoRuntimeDepsTest and Capstone.Credo.Check.Design.NoRuntimeDeps enforce that mechanically on every commit — see goals.md for why it matters.

Getting started

mix archive.install hex capstone
mix capstone.new --path target.exs

target.exs is a small Elixir literal describing the project to generate:

%{
schema_version: 1,
base: :api,
project: [name: "my_app", github_org: "acme"],
plugins: []
}

base is :api, :web, or :both; project.module and project.app are optional and derived from name when omitted. plugins is a list of plugin type atoms — this package ships :cache, :openapi and :prod_image_api — resolved and applied during generation, before dependencies are fetched. See Building a plugin and Applying a plugin for how that works.

Once a project exists, adding a plugin to target.exs and running mix capstone.update applies it without regenerating anything — see Upgrading the installation.

A project generated by Capstone already carries capstone as a dependency — it is what keeps that project upgradable for the rest of its life. Add it by hand only when adopting Capstone into a project that was not generated by it:

def deps do
[
{:capstone, "~> 0.1"}
]
end

A version-skew guard (Capstone.VersionGuard) catches the one case where a globally-installed archive and a project's own pinned dependency on it disagree.

Status

Pre-1.0 and under active development. The API is not yet stable — see goals.md for the design record.

Versioning

A single .version file holds one bare x.y.z line, read by mix.exs at compile time.

mix devops.bump_version bumps it based on HEAD's Conventional Commit type (feat → minor, fix → patch, chore/test/build/ci → no bump — see config :devops, :commit_types in config/devops.exs for the full table) and amends that bump into the commit it describes. Run it by hand, or activate it as a post-commit hook once per checkout:

git config core.hooksPath scripts/hooks

Changelog

CHANGELOG.md is generated, not hand-written: mix devops.release runs git cliff (configured in cliff.toml) against full history, consolidating every tagged release into one section each. Commit groups mirror config/devops.exs's :commit_types table — a commit type that doesn't bump the version (test, chore, build, ci) doesn't appear in the changelog either.

Gates

Every commit is expected to satisfy:

mix format --check-formatted
mix credo --strict
mix coveralls # the suite plus the 100% line-coverage gate
mix dialyzer
mix doctor

mix credo --strict fails while a TODO(capstone) marker exists — see goals.md for why that is a feature, not friction.

Documentation

Generated API reference: https://hexdocs.pm/capstone

Licence

MIT — see LICENSE.