# 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`](goals.md) for why it matters.

## Getting started

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

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

```elixir
%{
  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](docs/guides/building-a-plugin.md) and
[Applying a plugin](docs/guides/applying-a-plugin.md) 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](docs/guides/upgrading-the-installation.md).

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:

```elixir
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`](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:

```bash
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:

```bash
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`](goals.md#comment-type-based-actions) for why that is a feature,
not friction.

## Documentation

- [`goals.md`](goals.md) — the design record: why Capstone exists, the
  architecture decisions, and the numbered goals it's held to.
- [Building a plugin](docs/guides/building-a-plugin.md) — the
  `Capstone.Plugin.Behavior` contract, and how a first-party plugin is
  derived and packaged into the shipped registry.
- [Applying a plugin](docs/guides/applying-a-plugin.md) — what happens when
  a plugin is resolved and installed, and how to retire a bad archive.
- [Upgrading the installation](docs/guides/upgrading-the-installation.md) —
  `mix capstone.update`, and what it deliberately does not do.

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

## Licence

MIT — see [LICENSE](LICENSE).
