···11+If more than one of the rules conflict, ask before implementing.
22+33+## rules
44+55+- Always use `elixir-conventions` for elixir code. If you don't have this skill, stop and tell your user to talk to Adam, because you are prohibited from editing files in this project with it.
66+- Evolve the code without planning for every possible future or edge case.
77+- Delete abandoned paths by default when changing direction, except when required by compatibility/migration. Ask before keeping more than one implementation.
88+- Ensure backwards compatibility or migration paths for changes that affect contracts between components (e.g. agent/server), but otherwise assume breaking changes are ok.
99+- Never break deployments or strand agents such that they cannot apply an upgrade.
1010+- You can access the dev server live over tidewave project_eval, allowing for introspection of a live environment.
1111+- Do not create worktrees unless explicitly asked. When asked, use: `git worktree add .claude/worktrees/<name> -b <name>`
···11# Sower
2233-> Then he told them many things in parables, saying: “A farmer went out to sow his seed. As he was scattering the seed, some fell along the path, and the birds came and ate it up. Some fell on rocky places, where it did not have much soil. It sprang up quickly, because the soil was shallow. But when the sun came up, the plants were scorched, and they withered because they had no root. Other seed fell among thorns, which grew up and choked the plants. Still other seed fell on good soil, where it produced a crop—a hundred, sixty or thirty times what was sown. Whoever has ears, let them hear.”
33+Sower is a deployment and lifecycle management tool for Nix based configurations, including NixOS and Home-Manager.
44+55+With sower we sow the seeds of our systems.
66+77+- A seed is an extra bundle of metadata for an artifact path, e.g. a Nix store path.
88+- Seed metadata includes a set of tags, with git and user-provided tags.
99+- An agent defines seeds they want to subscribe to.
1010+- Seeds are submitted to a server to be used for deployments.
1111+1212+**WARNING**
1313+This project is experimental and is not recommended for production installation.
1414+One of the goals is never break deployments, but it is **not guaranteed yet**.
1515+I'm only using this in a homelab with approximately a dozen agents.
1616+This means the risk to me of breaking deployments is moderately low.
1717+1818+I'd love for others to get value out of what I'm building here.
1919+Please reach out if you're a user, I want to chat. :)
2020+2121+## Installation
2222+2323+Read the NixOS modules for the server and the agent. There is an example in nix/tests/e2e.nix
2424+2525+1. An example server config exists in nix/tests/e2e.nix
2626+2. An example agent config is below.
2727+2828+Good luck, everyone's counting on you.
2929+3030+## Components
3131+3232+- Server including Phoenix LiveView web interface.
3333+- Always-on Agent with bi-directional communication with the Server over WebSockets.
3434+- Activator used by the Agent for running specific actions as root, over a systemd initiated socket.
3535+- CLI for submitting seeds including a full code to submitted builder.
3636+3737+### Agents
4383939+Agents have full control over what the seeds from the server can or will do.
4040+This is managed through their configuration.
4141+4242+#### Subscriptions
4343+4444+Subscriptions are the main controls for how systems are deployed. They include:
4545+4646+- A set of (currently primitive) seed tag matching rules
4747+- Schedule in cron format for pull-based deployments
4848+- Which deployment profile to use
4949+5050+#### Deployment Profiles
5151+5252+Controls for what happens when the deploy occurs.
5353+5454+- Arguments to pass to activation
5555+- Rules about rebooting (NixOS seeds only)
5656+5757+#### Example agent config
5858+5959+```nix
6060+{
6161+ age.secrets.sower-next-api-token = {
6262+ file = cfg.access_token_secret;
6363+ owner = "sower-agent";
6464+ };
6565+6666+ services.sower = {
6767+ activator = {
6868+ package = inputs.sower-next.packages.${pkgs.stdenv.hostPlatform.system}.activator;
6969+ allowedGroups = [ "users" ];
7070+ };
7171+7272+ agent = {
7373+ enable = true;
7474+ accessTokenFile = config.age.secrets.sower-next-api-token.path;
7575+ package = inputs.sower-next.packages.${pkgs.stdenv.hostPlatform.system}.agent;
7676+7777+ settings = {
7878+ access_token_file = config.age.secrets.sower-next-api-token.path;
7979+ endpoint = "http://localhost:7150";
8080+8181+ deployment_profiles = {
8282+ boot = {
8383+ activation_args = [ "boot" ];
8484+ reboot_policy = "when-required";
8585+ };
8686+ switch = {
8787+ activation_args = [ "switch" ];
8888+ reboot_policy = "never";
8989+ };
9090+ };
9191+9292+ subscriptions = [
9393+ {
9494+ seed_name = config.networking.hostName;
9595+ seed_type = "nixos";
9696+ rules = [ "git_branch=main" ];
9797+ # https://hexdocs.pm/crontab/cron_notation.html
9898+ schedule = "0 3";
9999+ deployment_profile = "boot";
100100+ }
101101+ ];
102102+ };
103103+ };
104104+ };
105105+106106+ users.users.adam.extraGroups = [ "sower-activator" ];
107107+};
108108+```