Teams¶
A team keeps its shared state in one Git repository: its roster, each person's preferences, the team's workflow contracts, inventory and policies. The repository's URL is the invite, and the code host's permissions decide who may read it. Nothing in it configures anyone's machine.
Join your team¶
Someone posts the team repository's URL in chat. You run:
hz team join https://github.com/acme-example/hz-team-payments.git
hz clones it with your own git access, reads who you are from the GitHub login gh is signed in as, and looks you up
in the roster. It then shows what is left: making it your team ([team] in your user configuration). Nothing waits
for you but that; add --yes to go ahead:
hz team join https://github.com/acme-example/hz-team-payments.git --yes
Not on the roster? You can still read the team's contracts. Ask to be added: --propose opens a pull request that adds
you, which the team's owners merge. If the roster lists you without a login, claim that entry with --handle <entry>.
gh not signed in? Say who you are with --login <your GitHub login>.
Your team's plugin, the one hz.yaml names, is your layer: hz system layer show shows it stacked on your
company's, org's and site's plugins (Playbooks: layers). Install it with
hz system plugin add <plugin>; another layer is yours with hz system config set team.layer <layer>.
Create a team¶
hz team new payments --github acme-example/hz-team-payments --roster github:acme-example/payments
This creates the repository from a template, makes you its first owner, and drafts the roster from a GitHub team you
can read; everyone drafted starts as engineer, and you fix roles in a commit. Without --github the repository
exists only on your machine until you push it.
The repository holds:
| Path | What | Who approves changes |
|---|---|---|
hz.yaml |
the team's name, the roles that own the roster, its plugin if it has one | owners |
team/roster.yaml |
handle, GitHub login, roles and dates of each member; no names, titles or managers | owners |
people/<handle>.yaml |
each person's preferences | that person |
workflows/ |
team contracts (WORKFLOWS), checked by the repository's Actions workflow | owners and members |
inventory/, policies/ |
declared artefacts and systems; owned policies | owners |
CODEOWNERS says who approves what. GitHub enforces it only when the default branch requires a pull request reviewed by code owners; set that rule in the repository's settings.
What your team recommends¶
A team's hz.yaml may recommend what its members use. It only recommends: nothing in it binds, installs, stores or
schedules anything on your machine.
recommend:
plugins: [heinzel-google]
bindings: {documents: google, tracker: github}
credentials: [google/oauth-client] # names only, never values
contracts: [weekly-status] # team contracts in workflows/
hz org sync shows each recommendation beside what you have, and where it comes from. --accept <ids> (or all)
writes what you accept to your user file: a binding to [capabilities], a contract to [heinzel] schedule_team,
pinned to the content you read with hz heinzel show team:<name>. all takes only what you have no choice for yet;
what you chose otherwise switches only when you name it. Plugins and credentials stay commands you run yourself, which
sync names. hz system doctor says when recommendations wait for you. An entry hz can't check is dropped, and
hz team show says which.
Your team's layer plugins recommend too: sync lists the capability bindings their playbooks recommend, the most
specific layer's for each capability, with the layer as the origin; the team repository's recommendation wins for the
same capability (Playbooks: layers).
Add someone, show, leave¶
hz team add theo --login theo-example --role engineeradds someone to the roster, as an owner: a pull request, or a commit for a repository without a remote.--by <your login>says who you are whenghis signed in as someone else.hz team showlists the team, its checkout and its members, and what is wrong with them;hz system doctorchecks the same.- To leave:
hz system config unset team.checkout && hz system config unset team.repository.
Is the work flowing¶
Each run of a scheduled team contract is a promise: its artifact, by the next run of a contract that reads it (or else
its own next run). Your Heinzelmännchen report what they did, and hz graph says whether each promise is kept
(ADR 0054):
hz system config set report.user costas # once: your roster handle
hz report drafted costas-tracker https://tracker.acme.example/boards/7#costas --contract team:tracker-update --part costas
hz report approved costas-tracker https://tracker.acme.example/boards/7#costas costas --contract team:tracker-update --part costas
hz report heartbeat costas-tracker # alive; silent for 2 days shows as offline
hz report sync # copy your logs into the checkout, then commit and push
hz graph # "Weekly report waiting on 2 updates", weeks, states
hz graph --heinzel costas-tracker --json # JSON Graph Format, docs/schemas/team-graph-1.json
A promise is on_time, waiting_for_approval, late, fell_back (kept on a stale input) or offline. The graph is the
team layer only: entries are metadata (who, when, which verb, on what), never content, descriptions reach no graph, and
nothing is counted per person. Your sessions, drafts and edits stay yours. Logs live in your state directory, one per
Heinzelmännchen, and in telemetry/<handle>/<id>.jsonl in the team repository, one writer each; sync refuses a copy
your log doesn't extend. Pushing is still yours; automatic sync is the next step.
The graph keeper watches it for you: hz heinzel new keeper --template graph:team-graph-keeper writes a contract that
reads the graph and drafts a morning note for you alone; uncomment its schedule when its drafts read right.
Your own state repository¶
hz notes, on your machine, the days you used it (one line a day: no time, no count, no command) and each version it
ran. Nothing of it leaves until you name a private repository of your own; then the daemon pushes what is new every
15 minutes to this machine's branch hz/<handle>/<machine>, fast-forward only, with your git credentials
(ADR 0081):
hz system config set system.state.personal https://github.com/mira-example/heinzel-state-mira # private, yours
hz system state push # now, rather than within 15 minutes
hz system state status # where it goes, what is pending, the last push
The machine id is random, never the host name. Each branch has one writer: a branch that moved to commits this
machine didn't make stops the push (HZS001) instead of being overwritten; delete the branch if they aren't yours,
then hz system state reset. Sharing with your team comes next, only after you say yes, and aggregate unless you say
yes again to being named.
What waits for your yes¶
new, join and add show every step, with the command it runs, before it happens. Reading (a clone into hz's data
directory) runs at once. Steps that change something outside your machine (creating a repository, pushing, opening a
pull request) and making a team yours wait for --yes. The commands are CLI and MCP only.
An existing checkout from the deprecated [heinzel] team_repository becomes your team with hz team adopt <path>.