Make mu the company chart: the eight products, the site's logo, む, adr-verbatim

- mu is piabrota's company chart, not an umbrella, and the README header is centred.
- products/ holds pirsig, alerts, ihero, gramatico, nix-os, dojo, rax and agents. The yggdrasil and
  asgard submodules go; our forks of them stay in the index.
- PIABROTA.md follows the org as it is now: 24 public repos.
- The logo is the eye that piabrota.art shows. む is drawn in pure Nix, with nix-os' pen, and checked by
  the flake.
- .claude/skills/adr-verbatim is copied unchanged from davidondrej/cloudroom, under Apache-2.0, with
  credit in NOTICE.md.
- The map shows the eight products, and the portfolio figure goes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Matheus HoffmannandClaude Opus 5.5 committed 2026-11-01 05:23:40 -03:00
1 parent fd1d404c4f
commit 1a0f30f9af
47 files changed
+2215 -326

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
# Skills
Agent skills this repo vendors. Refresh a skill by copying upstream again, never by editing its body.
| Skill | Upstream | Licence |
| --- | --- | --- |
| [`adr-verbatim`](adr-verbatim/SKILL.md) | [davidondrej/cloudroom](https://github.com/davidondrej/cloudroom/blob/6f6cb7fd0665624c29fa4cbbed46d0dc7b1f9f84/skills/adr-verbatim/SKILL.md), by David Ondrej, copied unchanged at `6f6cb7f` | [Apache-2.0](../../LICENSES/Apache-2.0.txt) |
+35
View File
@@ -0,0 +1,35 @@
---
name: adr-verbatim
description: 'Record concise ADRs that preserve the user''s decisions without conversational noise. Use for "adr-verbatim", "new ADR", "document that as an ADR", "record this decision", or supplied ADR wording.'
---
# ADR Verbatim
Preserve the user's meaning, not the conversation transcript. Record only the decision and context needed to understand it.
## Steps
1. Extract the decision the user stated or approved in the conversation. Ask only if the decision is unclear; do not require him to dictate polished wording.
2. Use the project's established ADR location, including a previously specified repository. Do not assume the current checkout owns the ADRs. Name the file by that directory's rule (check its README or AGENTS.md); if it has none, take the next number.
3. Write a short, clear ADR. Remove filler, emotional reactions, repetition, rhetorical questions, and instructions to the agent. Fix grammar and clarify references without changing the meaning, scope, conditions, or priorities.
4. Check every statement against the user's decision. Remove invented requirements and unapproved agent suggestions.
5. Show the saved path and full ADR in a code block.
## Format
Match the directory's filenames, such as `docs/adr/0042-short-slug.md` or `docs/adr/20261030-175900-short-slug.md`. Use the file's ID in the heading.
```markdown
# <ID> — short title
Status: accepted (<decision owner>, YYYY-MM-DD)
<The decision in plain English.>
```
## Rules
- Prefer a short paragraph or list. Add sections only when they improve clarity.
- Do not add speculative rationale, alternatives, consequences, or implementation details.
- Use exact wording only when the user explicitly asks for an exact quote or verbatim passage.
- A changed decision needs a new ADR. Correct an existing ADR when the user explicitly requests it, without changing unrelated history.
+24 -6
View File
@@ -1,9 +1,27 @@
[submodule "products/yggdrasil"]
path = products/yggdrasil
url = https://github.com/piabrota/yggdrasil.git
[submodule "products/asgard"]
path = products/asgard
url = https://github.com/piabrota/asgard.git
[submodule "forks/archify"]
path = forks/archify
url = https://github.com/piabrota/archify.git
[submodule "products/pirsig"]
path = products/pirsig
url = https://github.com/piabrota/pirsig.git
[submodule "products/alerts"]
path = products/alerts
url = https://github.com/piabrota/alerts.git
[submodule "products/ihero"]
path = products/ihero
url = https://github.com/piabrota/ihero.git
[submodule "products/gramatico"]
path = products/gramatico
url = https://github.com/piabrota/gramatico.git
[submodule "products/nix-os"]
path = products/nix-os
url = https://github.com/piabrota/nix-os.git
[submodule "products/dojo"]
path = products/dojo
url = https://github.com/piabrota/dojo.git
[submodule "products/rax"]
path = products/rax
url = https://github.com/piabrota/rax.git
[submodule "products/agents"]
path = products/agents
url = https://github.com/piabrota/agents.git
+9 -3
View File
@@ -1,7 +1,7 @@
# AGENTS.md: piabrota
piabrota is the company, an open software fabric made in Rio de Janeiro. This umbrella, `mu`, holds the
company docs, the standards every product inherits, and the products as submodules under `products/`.
piabrota is the company, an open software fabric made in Rio de Janeiro. This repo, `mu`, is its company
chart: it holds the company docs, the standards every product inherits, and the eight products as submodules under `products/`.
Read [`DOGMA.md`](DOGMA.md) first: it wins over this file. [`PIABROTA.md`](PIABROTA.md) indexes the org's
repos. Start with `docs/README.md`.
@@ -37,6 +37,11 @@ loosen these.
- Research and journal: `docs/5-research/`, `docs/6-journal/`.
- Brand: `docs/7-branding/` (identity, voice, the naming record).
## Skills
`.claude/skills/` vendors skills ([the list and their credits](.claude/skills/README.md)). `adr-verbatim` records a decision: in this
repo, write it as a permanent note in `brain/`, as the next section says.
## The brain
[pirsig](https://github.com/piabrota/pirsig) will manage this repo. `brain/` is its fork state, and
@@ -60,7 +65,7 @@ you run it. If you write a reusable script, it goes here, never only in a scratc
| --- | --- |
| Push, open a pull request or read GitHub as `piabrota-pr-bot` | `scripts/as-bot.sh <repo> <cmd>`; `--read all` to read. The only way an agent reaches GitHub; to open a pull request, `scripts/pr-open.sh` is the default |
| Open a pull request as `piabrota-pr-bot` and arm auto-merge on it: the default way an agent opens one. A human's approval still decides the merge; if arming fails the PR stays open and the script says why. A PR stacked on a branch other than the default one is opened without auto-merge | `scripts/pr-open.sh <repo> [gh pr create args]`, e.g. `scripts/pr-open.sh gleipnir --base main --head my-branch --title "…" --body-file body.md`. Prints the PR's URL. Never merges directly, never `--admin` |
| Build `ygg` from the umbrella's checkouts, so a smoke or proof run never uses a stale one | `scripts/ygg-build.sh [--yggdrasil DIR] [--out FILE [--beside-path]] [--allow-behind] [--force]`. Refuses a dirty module or one behind its local `origin/main` (it fetches nothing); builds to the `ygg` first on PATH (else `$(go env GOPATH)/bin/ygg`) and writes the commits to `OUT.build.txt`; a link is followed to its target; an error if `command -v ygg` is not OUT, unless `--beside-path` (needs `--out`): a second ygg beside the one on PATH, built with its facts, and the script prints `YGG_CMD=OUT` to run it. Never overwrites a file that is not a Go binary without `--force`. The smoke and proof scripts refuse a `ygg` from PATH, or a `YGG_CMD` of one executable file, whose facts do not name odin's HEAD (`--any-ygg` skips that; a `YGG_CMD` of several words is used unchecked) |
| Build `ygg` from this repo's checkouts, so a smoke or proof run never uses a stale one | `scripts/ygg-build.sh [--yggdrasil DIR] [--out FILE [--beside-path]] [--allow-behind] [--force]`. Refuses a dirty module or one behind its local `origin/main` (it fetches nothing); builds to the `ygg` first on PATH (else `$(go env GOPATH)/bin/ygg`) and writes the commits to `OUT.build.txt`; a link is followed to its target; an error if `command -v ygg` is not OUT, unless `--beside-path` (needs `--out`): a second ygg beside the one on PATH, built with its facts, and the script prints `YGG_CMD=OUT` to run it. Never overwrites a file that is not a Go binary without `--force`. The smoke and proof scripts refuse a `ygg` from PATH, or a `YGG_CMD` of one executable file, whose facts do not name odin's HEAD (`--any-ygg` skips that; a `YGG_CMD` of several words is used unchecked) |
| Clean up after runs that have ended: the empty pods and leftover containers | `scripts/ygg-clean.sh --dry-run [--folder DIR] [--keep PROJECT]... [PROJECT...]`, then without `--dry-run`. Runs `ygg doctor` on each project under DIR (default `~/ygg-it`) with the config its runs used; skips a project with a live run (its lock in `/proc/locks`, or open in a process) and refuses when it cannot tell; never deletes a run, a project or an image, and never starts or stops the engine |
| Set up and check the GPU for the engine: the NVIDIA toolkit (pinned 1.20.1) and the CDI spec in the Podman machine's distro on WSL2, repeatable after a driver update or on a new machine | `scripts/ygg-gpu.sh setup\|check [--machine NAME] [--folder DIR]`. `setup` installs only what is missing and regenerates a stale spec, then runs `check`; `check` runs the CUDA image (by digest) through `ygg-engine.sh` and prints `gpu: <name> <memory>`, or exits 3 with `missing: toolkit\|spec\|stale spec` and the fix, or 2 when the engine does not answer. Root commands go through `wsl.exe -u root`, never sudo; it never starts, stops or re-creates the machine |
| Set up, start, stop, check and clean the local model server (llama-server and the model gate in one container, on the engine's GPU), from the operator's model list; the qwen scripts find it through it | `scripts/ygg-models.sh [--models FILE] [--folder DIR] setup [--weights DIR] [--state DIR] [--price IN:OUT[:CACHE_READ]] [--model NAME]` does the first-time setup and is safe to run again: the GPU (`ygg-gpu.sh`), the list from the example when FILE is missing (`--price` required then; folders default to `DIR/models/weights` and `DIR/models/state`), the missing `download` files (`hf`, else `uvx`), the image, start, load (the first model unless `--model`) and the chat template when it is missing. `clean [--state] [--weights]` removes the container, the network and the image, and refuses, changing nothing, while another container is on the network; `--state` the preset and allow files; `--weights` only the files the list downloads and `.cache/huggingface` under the weights folder. Also `start\|stop\|status\|load NAME\|template NAME`. FILE defaults to `${XDG_CONFIG_HOME:-~/.config}/ygg/models.yaml` and DIR (holds `factory.yaml`, which names the engine) to `~/ygg-it` (example list: `scripts/testdata/models/models.example.yaml`). `start` runs `ygg-gpu.sh check` first (a stale spec is set up again), builds the image only when its tag is missing (long, CUDA), creates the internal network when absent, writes the preset and runs the container with `127.0.0.1:<host_port>` as its only published port; `status` prints `running on <url>, loaded: <name\|none>` or exits 3; `stop` keeps the network and the image. Engine calls go through `ygg-engine.sh` |
@@ -81,6 +86,7 @@ you run it. If you write a reusable script, it goes here, never only in a scratc
| Check the journal against spec §10.5 and design criterion 6: front matter, sections, the index, evidence once resolved, a `factory-change` entry citing `ygg metrics --compare` | `scripts/journal-check.sh [DIR]` |
| Scaffold a new Rust component, rendered by `minijinja-cli` | `scripts/scaffold-component.sh` |
| Render `PIABROTA.md` from `scripts/piabrota/repos.toml`, or check that it is fresh | `scripts/piabrota-index.sh [--check]` |
| Write the README drawings, the logo and む, from `drawings/*.nix`; `nix flake check` checks it | `scripts/drawing.sh` |
| Draw every plot with archify, or check that the PNGs are fresh | `scripts/figure.sh draw\|check`. Sources in `docs/archify/`, PNGs in `docs/img/`, the pinned archify in `forks/archify` |
Only the founder runs `scripts/new-repo.sh`, `scripts/create-repo.sh`, `scripts/add-licences.sh`, `scripts/add-ci.sh`,
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+6 -2
View File
@@ -1,7 +1,7 @@
# Notice
piabrota/mu started as a copy of [ouroboric-dev/ouroboric](https://github.com/ouroboric-dev/ouroboric),
the company umbrella of Ouroboric, by Bruno Guilhermo de Barros Valério. This notice keeps that credit,
the company repo of Ouroboric, by Bruno Guilhermo de Barros Valério. This notice keeps that credit,
as the licences require.
- **What came from there:** the standards in `docs/4-ways-of-working/`, the scripts in `scripts/`,
@@ -10,7 +10,7 @@ as the licences require.
CC BY 4.0. See [`REUSE.toml`](REUSE.toml).
- **What changed:** on 2026-11-01 piabrota changed the identity of the copy: names, org, bot, palette,
charter, roadmap, budget, legal page and README. It removed Ouroboric's logos and logo prompts, and
replaced the Go component template with a Rust one and the D2 and Mermaid diagrams with archify
swapped the products for piabrota's own, replaced the Go component template with a Rust one and the D2 and Mermaid diagrams with archify
figures. `git log` holds every change.
- **What did not change:** dated records (`docs/6-journal/`, dated files in `docs/5-research/`,
`docs/1-company/readiness/`) stay as written, under the name Ouroboric. Only their links to removed
@@ -19,3 +19,7 @@ as the licences require.
The names Ouroboric, Yggdrasil, Asgard and their modules are not ours. See
[TRADEMARKS.md](TRADEMARKS.md). Ouroboric is a partner of piabrota; this notice does not say that
Ouroboric endorses this repository.
`.claude/skills/adr-verbatim/` is copied unchanged from
[davidondrej/cloudroom](https://github.com/davidondrej/cloudroom), by David Ondrej, under Apache-2.0.
`drawings/pen.nix` comes from [piabrota/nix-os](https://github.com/piabrota/nix-os).
+11 -13
View File
@@ -2,18 +2,20 @@
# PIABROTA
Every public repo of [piabrota](https://github.com/piabrota), an open software fabric made in Rio de
Janeiro: 28 public repos, as of 2026-11-01. The rules
are in [DOGMA.md](DOGMA.md). The org's 2 private repos are counted, never listed.
Janeiro: 24 public repos, as of 2026-11-01. The rules
are in [DOGMA.md](DOGMA.md).
## Umbrella
## Company
| Repo | Licence | What it is |
| --- | --- | --- |
| [`mu`](https://github.com/piabrota/mu) | CC BY 4.0, AGPL-3.0, MPL-2.0 | The company umbrella: dogma, charter, standards, journal, brand and the scripts every project inherits. |
| [`mu`](https://github.com/piabrota/mu) | CC BY 4.0, AGPL-3.0, MPL-2.0 | The company chart: dogma, charter, standards, journal, brand and the scripts every project inherits. |
| [`.github`](https://github.com/piabrota/.github) | MPL-2.0 | The org's profile, with the project table, the fabric figure and the funding links. |
## Projects
The projects are the submodules under [`products/`](products/).
| Repo | Lane | Licence | What it is | Its place in the company |
| --- | --- | --- | --- | --- |
| [`pirsig`](https://github.com/piabrota/pirsig) | think and write | MPL-2.0 | A second brain: PARA and a Zettelkasten slip-box. A Rust app with a desktop app, a REST API and the `psg` CLI, on one model layer. | Will manage this repo: `brain/` is its fork state. |
@@ -22,7 +24,8 @@ are in [DOGMA.md](DOGMA.md). The org's 2 private repos are counted, never listed
| [`rax`](https://github.com/piabrota/rax) | warn and host | MPL-2.0, parts Apache-2.0 | Rustic Agentic Runtime: a pure-Rust port of AX, the declarative orchestrator for agentic tasks, with AX's API. | Runs the agents' tasks on the VPS, one pod per run. |
| [`agents`](https://github.com/piabrota/agents) | warn and host | MPL-2.0 | Small agents that watch nix-os and its VPS: deploy doctor, pull request reviewer, mentions, mirror keeper, flake annotator, feedback, health digest. | Act on GitHub as the App `piabrota-ops`, installed on nix-os only. |
| [`nix-os`](https://github.com/piabrota/nix-os) | warn and host | MPL-2.0 | The NixOS configuration of the small VPS that serves piabrota.art. A merge to `main` is a deploy. | Hosts the site, rax, the agents and PGX. |
| [`ihoje`](https://github.com/piabrota/ihoje) | archived | no licence file | A Rust event scraper with anime-inspired module names. Archived and no longer maintained. | None. |
| [`ihero`](https://github.com/piabrota/ihero) | play | MPL-2.0 | A FOSS music player and game, in Rust. Coming: the repo holds only its licence. | None yet. |
| [`dojo`](https://github.com/piabrota/dojo) | not set | MPL-2.0 | 道場. Empty so far: a licence and a title. | None yet. |
## Forks
@@ -33,9 +36,9 @@ its upstream's: no fork carries commits of its own.
| Repo | Upstream | Sync | Why it is here |
| --- | --- | --- | --- |
| [`cloudroom`](https://github.com/piabrota/cloudroom) | [`davidondrej/cloudroom`](https://github.com/davidondrej/cloudroom) | 2 behind | A platform to run many agents; this repo vendors its `adr-verbatim` skill. |
| [`skills`](https://github.com/piabrota/skills) | [`davidondrej/skills`](https://github.com/davidondrej/skills) | even | Agent skills. |
| [`relay`](https://github.com/piabrota/relay) | [`ronaknnathani/relay`](https://github.com/ronaknnathani/relay) | even | Skills that orchestrate coding agents on long tasks. |
| [`rea`](https://github.com/piabrota/rea) | [`morluto/rea`](https://github.com/morluto/rea) | 761 behind | Reverse engineering with agents. |
| [`TencentDB-Agent-Memory`](https://github.com/piabrota/TencentDB-Agent-Memory) | [`TencentCloud/TencentDB-Agent-Memory`](https://github.com/TencentCloud/TencentDB-Agent-Memory) | even | A team-level memory hub for agents. |
| [`axon`](https://github.com/piabrota/axon) | [`danieltamas/axon`](https://github.com/danieltamas/axon) | even | Reads agent harness logs: speed, cost and output per model. |
| [`bton`](https://github.com/piabrota/bton) | [`danieltamas/bton`](https://github.com/danieltamas/bton) | 11 behind | A team's review flow with coding agents, from the macOS menu bar. |
@@ -52,10 +55,6 @@ its upstream's: no fork carries commits of its own.
| Repo | Upstream | Sync | Why it is here |
| --- | --- | --- | --- |
| [`core`](https://github.com/piabrota/core) | [`home-assistant/core`](https://github.com/home-assistant/core) | 795 behind | Home Assistant: local home automation. |
| [`edit`](https://github.com/piabrota/edit) | [`fmhy/edit`](https://github.com/fmhy/edit) | 7 behind | Changes to FMHY. |
| [`prj-gd-engine`](https://github.com/piabrota/prj-gd-engine) | [`mbracali/prj-gd-engine`](https://github.com/mbracali/prj-gd-engine) | 179 behind | Re-implementations of guitar music games. |
| [`naruto-unison`](https://github.com/piabrota/naruto-unison) | [`naruto-unison/naruto-unison`](https://github.com/naruto-unison/naruto-unison) | even | Naruto Unison, a game. |
| [`OpenVoice`](https://github.com/piabrota/OpenVoice) | [`myshell-ai/OpenVoice`](https://github.com/myshell-ai/OpenVoice) | even | Instant voice cloning. |
### Runtimes and compilers
@@ -64,11 +63,10 @@ its upstream's: no fork carries commits of its own.
| [`pgx`](https://github.com/piabrota/pgx) | [`pgrundev/pgx`](https://github.com/pgrundev/pgx) | even | Postgres-compatible engine in Rust; nix-os runs it for rax's store. |
| [`rust-cuda`](https://github.com/piabrota/rust-cuda) | [`Rust-GPU/rust-cuda`](https://github.com/Rust-GPU/rust-cuda) | even | GPU code in Rust. |
| [`lean_kernel_verify`](https://github.com/piabrota/lean_kernel_verify) | [`facebookresearch/lean_kernel_verify`](https://github.com/facebookresearch/lean_kernel_verify) | even | A compiler-based safety checker for GPU kernels, in Lean 4. |
| [`thc`](https://github.com/piabrota/thc) | [`ekmett/thc`](https://github.com/ekmett/thc) | even | The Turbo Haskell Compiler. |
### The factory
| Repo | Upstream | Sync | Why it is here |
| --- | --- | --- | --- |
| [`yggdrasil`](https://github.com/piabrota/yggdrasil) | [`ouroboric-dev/yggdrasil`](https://github.com/ouroboric-dev/yggdrasil) | even | Submodule of this repo: the agentic factory. |
| [`asgard`](https://github.com/piabrota/asgard) | [`ouroboric-dev/asgard`](https://github.com/ouroboric-dev/asgard) | even | Submodule of this repo: the kickstart realm. |
| [`yggdrasil`](https://github.com/piabrota/yggdrasil) | [`ouroboric-dev/yggdrasil`](https://github.com/ouroboric-dev/yggdrasil) | even | The agentic factory this repo inherited its method from. |
| [`asgard`](https://github.com/piabrota/asgard) | [`ouroboric-dev/asgard`](https://github.com/ouroboric-dev/asgard) | even | The kickstart realm of that factory. |
+14 -11
View File
@@ -1,30 +1,33 @@
<img alt="無, mu, no thing: the kanji brushed in twelve strokes, from pirsig" src="https://raw.githubusercontent.com/piabrota/pirsig/b7dd1da2ac886845b14bb90e5d8d34976cfc95cb/docs/drawings/pirsig.svg" width="200"/>
<!-- markdownlint-disable MD033 -->
<div align="center">
<img alt="The piabrota logo, as piabrota.art shows it: an open green eye on red" src="docs/drawings/eye.svg" width="160"/>
<img alt="む, mu, brushed in its three strokes, in pure Nix" src="docs/drawings/mu.svg" width="160"/>
# mu
無 · the piabrota umbrella · [dogma](DOGMA.md) · [repos](PIABROTA.md) · [decision models](docs/DECISION_MODELS.md) · [charter](docs/1-company/charter.md) · [licence](#licence)
<sub>the piabrota company chart · <a href="DOGMA.md">dogma</a> · <a href="PIABROTA.md">repos</a> · <a href="docs/DECISION_MODELS.md">decision models</a> · <a href="docs/1-company/charter.md">charter</a> · <a href="#licence">licence</a></sub>
</div>
## In one minute
- **mu is the company umbrella of [piabrota](https://github.com/piabrota)**, an open software fabric
- **mu is the company chart of [piabrota](https://github.com/piabrota)**, an open software fabric
made in Rio de Janeiro. It holds the dogma, the charter, the standards, the journal and the tools
that every piabrota project inherits.
that every piabrota project inherits, and its eight products as submodules.
- **[DOGMA.md](DOGMA.md) holds the ten invariants.** Agents fix every error a user or an owner reports,
in short pull requests. Judgement is decision-oriented: evidence, a decision model, calibrated
probabilities, rules that humans define, a verdict.
- **[PIABROTA.md](PIABROTA.md) indexes every public repo of the org.**
- **[pirsig](https://github.com/piabrota/pirsig) will manage this repo:** smart notes, PARA and a
track record of high-level decisions. [`brain/`](brain/) is its fork state.
- **mu began as a copy of Ouroboric's umbrella.** [NOTICE.md](NOTICE.md) keeps that credit.
- **mu began as a copy of Ouroboric's company repo.** [NOTICE.md](NOTICE.md) keeps that credit.
## The map
![piabrota map: the founder approves direction in the Asgard realm (readiness checklist, kickstart graph later); Yggdrasil, the agentic factory, contains Odin, Jormungandr, Gleipnir, Havamal, Voluspa (the graph library, which gives Odin its graphs), the realms (Midgard and Helheim in v0, Jotunheim and Muspelheim later), the Asgard realm, and Ginnungagap (later), which creates realms, all honouring the Gungnir contract, with Ratatoskr, Norns, Mimir and Bragi later; the Asgard realm kickstarts and the other realms build companies and products, whose lessons and benchmarks feed back into piabrota](docs/img/piabrota-map.png)
![piabrota map: owners write the rules and approve direction in mu, the company chart, which pirsig manages; the products are gramatico and pirsig (think and write), alerts, rax, agents and nix-os (warn and host), ihero and dojo](docs/img/piabrota-map.png)
**How to read this figure.** Top to bottom, one lane per role. An arrow says what flows, and a red border marks a person or what the factory makes. The source is [`piabrota-map.json`](docs/archify/piabrota-map.json).
The factory's names come from Norse myth, and they are Ouroboric's; the
[naming and mythology record](docs/7-branding/story/naming-and-mythology.md) tells the story behind each one.
**How to read this figure.** Top to bottom, one lane per kind of work. A red border marks the people who steer. The source is [`piabrota-map.json`](docs/archify/piabrota-map.json).
## Contents
@@ -37,7 +40,7 @@ The factory's names come from Norse myth, and they are Ouroboric's; the
| [`7-branding/`](docs/7-branding/README.md) | the piabrota identity and voice, and the naming record |
| [`brain/`](brain/) | pirsig's fork state: PARA, smart notes, the track record |
The products are submodules under [`products/`](products/): clone with `--recurse-submodules`.
The eight products are submodules under [`products/`](products/): clone with `--recurse-submodules`.
## Contributing
+8 -1
View File
@@ -14,7 +14,14 @@ SPDX-License-Identifier = "AGPL-3.0-only"
# What piabrota wrote new is MPL-2.0, the org's licence.
[[annotations]]
path = ["DOGMA.md", "PIABROTA.md", "pirsig.toml", "brain/**", "docs/DECISION_MODELS.md", "docs/archify/**", "docs/img/**", "docs/mockups/**", "scripts/figure.sh", "scripts/minijinja-lib.sh", "scripts/piabrota-index.sh", "scripts/piabrota/**", "scripts/templates/piabrota/**", "scripts/templates/rust-component/**"]
path = ["DOGMA.md", "PIABROTA.md", "pirsig.toml", "brain/**", "docs/DECISION_MODELS.md", "docs/drawings/**", "drawings/**", "flake.nix", "flake.lock", ".claude/skills/README.md", "scripts/drawing.sh", "docs/archify/**", "docs/img/**", "docs/mockups/**", "scripts/figure.sh", "scripts/minijinja-lib.sh", "scripts/piabrota-index.sh", "scripts/piabrota/**", "scripts/templates/piabrota/**", "scripts/templates/rust-component/**"]
precedence = "closest"
SPDX-FileCopyrightText = "2026 piabrota contributors"
SPDX-License-Identifier = "MPL-2.0"
# adr-verbatim is copied unchanged from davidondrej/cloudroom; see .claude/skills/README.md.
[[annotations]]
path = [".claude/skills/adr-verbatim/**"]
precedence = "closest"
SPDX-FileCopyrightText = "2026 David Ondrej"
SPDX-License-Identifier = "Apache-2.0"
@@ -0,0 +1,21 @@
---
pirsig: note
zid: "13"
title: "The products are piabrota's own eight"
aliases: ["The products are piabrota's own eight"]
kind: permanent
tags: ["decision"]
created: 2026-11-01T08:10:31+00:00
updated: 2026-11-01T08:10:31+00:00
---
# The products are piabrota's own eight
**Decided 2026-11-01.** products/ holds pirsig, alerts, ihero, gramatico, nix-os, dojo, rax and agents. Yggdrasil and Asgard stop being products; our forks of them stay.
**Why:** The owner set the list.
**Outcome:** pending.
Part of [[1 Decisions the track record|Decisions: the track record]].
@@ -6,14 +6,14 @@ aliases: ["mu takes the piabrota identity"]
kind: permanent
tags: ["decision"]
created: 2026-11-01T07:14:51+00:00
updated: 2026-11-01T07:14:51+00:00
updated: 2026-11-01T08:02:10.995865+00:00
---
# mu takes the piabrota identity
**Decided 2026-11-01.** This repo stops being a copy of Ouroboric's umbrella and becomes piabrota's: names, org, bot, charter, brand.
**Decided 2026-11-01.** This repo stops being a copy of Ouroboric's company repo and becomes piabrota's company chart: names, org, bot, charter, brand.
**Why:** piabrota needs its own company umbrella, managed by pirsig.
**Why:** piabrota needs its own company chart, managed by pirsig.
**Outcome:** pending.
@@ -6,14 +6,14 @@ aliases: ["Yggdrasil's leaves stay upstream"]
kind: permanent
tags: ["decision"]
created: 2026-11-01T07:14:51+00:00
updated: 2026-11-01T07:14:51+00:00
updated: 2026-11-01T08:10:31.266469+00:00
---
# Yggdrasil's leaves stay upstream
**Decided 2026-11-01.** The submodules point to our forks of yggdrasil and asgard; links to the leaves stay on ouroboric-dev.
**Decided 2026-11-01.** Links to Yggdrasil's leaves stay on ouroboric-dev.
**Why:** Only those two repos were forked, and they mirror upstream.
**Why:** Only yggdrasil and asgard were forked, and they mirror upstream.
**Outcome:** pending.
+4 -4
View File
@@ -49,12 +49,12 @@ handover, `docs/` stays the source of truth.
## Portfolio
[PIABROTA.md](../../PIABROTA.md) lists every public project. The factory below came with this repo,
from Ouroboric. Our forks of `yggdrasil` and `asgard` mirror upstream, and they stay submodules here.
The products are pirsig, alerts, ihero, gramatico, nix-os, dojo, rax and agents, each a submodule under
[`products/`](../../products/). [PIABROTA.md](../../PIABROTA.md) lists every public repo.
![piabrota portfolio: the founder approves direction in the Asgard realm of Yggdrasil, the agentic factory; the Asgard realm kickstarts a company such as photografy and Yggdrasil's other realms (web frontends and backend in v0; games, mobile, art and research later) build its product; a future product factory is illustrative](../img/piabrota-portfolio.png)
![piabrota map: owners write the rules and approve direction in mu, the company chart, which pirsig manages; the products are gramatico and pirsig (think and write), alerts, rax, agents and nix-os (warn and host), ihero and dojo](../img/piabrota-map.png)
**How to read this figure.** Top to bottom: the founder steers, Yggdrasil works, a company comes out. The company is an example. The source is [`piabrota-portfolio.json`](../archify/piabrota-portfolio.json).
**How to read this figure.** Top to bottom, one lane per kind of work. A red border marks the people who steer. The source is [`piabrota-map.json`](../archify/piabrota-map.json).
## North-star measures
+10 -5
View File
@@ -11,15 +11,20 @@ style: reference
[PIABROTA.md](../../PIABROTA.md) indexes every public repo of the [`piabrota`](https://github.com/piabrota)
organisation. This page says how this repo's tree relates to them.
## Umbrellas
## The chart and the products
| Repository | Kind | Role |
| --- | --- | --- |
| [`mu`](https://github.com/piabrota/mu) | company umbrella | this repo: dogma, charter, standards, journal, brand; the products as submodules under [`products/`](../../products/) |
| [`yggdrasil`](https://github.com/piabrota/yggdrasil) | product umbrella | our fork of the agentic factory; it mirrors upstream |
| [`asgard`](https://github.com/piabrota/asgard) | product umbrella | our fork of the kickstart realm; it mirrors upstream |
| [`mu`](https://github.com/piabrota/mu) | company chart | this repo: dogma, charter, standards, journal, brand |
| `pirsig`, `alerts`, `ihero`, `gramatico`, `nix-os`, `dojo`, `rax`, `agents` | products | submodules under [`products/`](../../products/) |
## Upstream repos
## The factory
Our forks of [`yggdrasil`](https://github.com/piabrota/yggdrasil) and
[`asgard`](https://github.com/piabrota/asgard) mirror upstream. They are not products of piabrota. The
`ygg-*` scripts use clones of them beside this repo, not submodules.
### Upstream repos
Yggdrasil's leaves were not forked. They live in [`ouroboric-dev`](https://github.com/ouroboric-dev),
and the `ygg-*` scripts build them from there, so those links stay on upstream.
+3 -4
View File
@@ -11,11 +11,10 @@ style: direction
This roadmap sets the order of work, not dates. Each product keeps its own detailed roadmap.
0. **The conversion:** this repo takes the piabrota identity, the dogma and the repo index.
1. **The GitHub setup:** create `piabrota-pr-bot`, add the `protect-main` ruleset to `mu`, and pass
`scripts/check-repos.sh`.
1. **The GitHub setup:** create `piabrota-pr-bot`, add the `protect-main` ruleset to `mu`, then extend
`scripts/check-repos.sh`, which still lists `yggdrasil` and `asgard`, to the eight products.
2. **The handover to pirsig:** PARA, smart notes and the track record move from seed to daily use.
3. **The decision pipeline:** try the tracked [decision models](../DECISION_MODELS.md), then write the
decision engine's first rules.
4. **Routines:** agents fix reported errors, on local models, Claude and Kimi.
5. **Later:** follow [Yggdrasil's roadmap](https://github.com/piabrota/yggdrasil/blob/main/docs/1-product/roadmap.md)
from our fork, which mirrors upstream.
5. **The products:** ihero and dojo get their first release.
+1 -1
View File
@@ -13,7 +13,7 @@ routing and docs checks work the same everywhere.
## 1. Umbrella template
A node is one of three kinds: **company umbrellas** (for example, `mu`, or a company that
A node is one of three kinds: **company charts or umbrellas** (for example, `mu`, or a company that
the Asgard realm kickstarted), **product umbrellas** (for example, `yggdrasil`, a client gallery) and
**leaves**. Company
umbrellas use `1-company/` (charter, roadmap, legal, readiness) instead of `1-product/`, and hold the
+2 -2
View File
@@ -8,5 +8,5 @@ The source of the piabrota identity in this repo.
| [`voice/`](voice/README.md) | tone and copywriting rules |
| [`story/`](story/naming-and-mythology.md) | the record of the factory's Norse names, which are Ouroboric's |
The piabrota logo is the green eye over the word PIABROTA, on red. It is the org's GitHub avatar, and it
is not stored here. Ouroboric's logos were removed from this repo: see [NOTICE.md](../../NOTICE.md).
The company logo is [`eye.svg`](../drawings/eye.svg), the mark piabrota.art shows: an open green eye on red.
Its source is the site's code in piabrota/nix-os. Ouroboric's logos were removed from this repo: see [NOTICE.md](../../NOTICE.md).
+4 -7
View File
@@ -1,16 +1,13 @@
# piabrota
piabrota is an open software fabric made in Rio de Janeiro. This repository, `mu`, is the company
umbrella. Read the [dogma](../DOGMA.md) first, then the [charter](1-company/charter.md).
chart. Read the [dogma](../DOGMA.md) first, then the [charter](1-company/charter.md).
## The map
![piabrota map: the founder approves direction in the Asgard realm (readiness checklist, kickstart graph later); Yggdrasil, the agentic factory, contains Odin, Jormungandr, Gleipnir, Havamal, Voluspa (the graph library, which gives Odin its graphs), the realms (Midgard and Helheim in v0, Jotunheim and Muspelheim later), the Asgard realm, and Ginnungagap (later), which creates realms, all honouring the Gungnir contract, with Ratatoskr, Norns, Mimir and Bragi later; the Asgard realm kickstarts and the other realms build companies and products, whose lessons and benchmarks feed back into piabrota](img/piabrota-map.png)
![piabrota map: owners write the rules and approve direction in mu, the company chart, which pirsig manages; the products are gramatico and pirsig (think and write), alerts, rax, agents and nix-os (warn and host), ihero and dojo](img/piabrota-map.png)
**How to read this figure.** Top to bottom, one lane per role. An arrow says what flows, and a red border marks a person or what the factory makes. The source is [`piabrota-map.json`](./archify/piabrota-map.json).
The factory's names come from Norse myth; the [naming and mythology record](7-branding/story/naming-and-mythology.md) tells the story behind each one, and its
[long-term map](7-branding/story/naming-and-mythology.md#glossary) shows what comes after v0.
**How to read this figure.** Top to bottom, one lane per kind of work. A red border marks the people who steer. The source is [`piabrota-map.json`](./archify/piabrota-map.json).
## Contents
@@ -23,7 +20,7 @@ The factory's names come from Norse myth; the [naming and mythology record](7-br
| [`7-branding/`](7-branding/README.md) | the piabrota identity and voice, and the naming record |
| [`DECISION_MODELS.md`](DECISION_MODELS.md) | the decision models we track, and where routines run |
[PIABROTA.md](../PIABROTA.md) indexes every public repo of the org. The products are submodules under
[PIABROTA.md](../PIABROTA.md) indexes every public repo of the org. The eight products are submodules under
[`products/`](../products/): clone with `--recurse-submodules`.
Dated records in `5-research/`, `6-journal/` and `1-company/readiness/` keep the name Ouroboric, as
+1 -2
View File
@@ -1,5 +1,4 @@
piabrota-map 560
piabrota-map 680
piabrota-long-term-map 560
piabrota-portfolio 430
sdd-flow 430
readiness-levels 300
1 piabrota-map 560 680
2 piabrota-long-term-map 560 560
piabrota-portfolio 430
3 sdd-flow 430 430
4 readiness-levels 300 300
+4 -5
View File
@@ -1,5 +1,4 @@
piabrota-long-term-map db92c84d0059560a-208acba
piabrota-map 3a7eaf62f4c9b9ff-208acba
piabrota-portfolio ae9bc36d7f189f52-208acba
readiness-levels 097742394b192caf-208acba
sdd-flow 5cfa2a47d5d41f0e-208acba
piabrota-long-term-map 6e95c7abf2355a78-208acba
piabrota-map 5d20e923b5d1ad53-208acba
readiness-levels 8c52751f00327775-208acba
sdd-flow fd01389d3d214a0b-208acba
+97 -92
View File
@@ -2,7 +2,7 @@
"schema_version": 2,
"diagram_type": "workflow",
"meta": {
"title": "The map: piabrota, its factory and what it makes",
"title": "The map: piabrota and its eight products",
"locale": "en",
"quality_profile": "showcase",
"legend": {
@@ -16,138 +16,143 @@
"label": "Humans steer"
},
{
"id": "core",
"label": "Yggdrasil, the agentic factory"
"id": "chart",
"label": "The company chart"
},
{
"id": "realms",
"label": "Realms"
"id": "think",
"label": "Think and write"
},
{
"id": "out",
"label": "What it makes"
"id": "host",
"label": "Warn and host"
},
{
"id": "play",
"label": "Coming"
}
],
"mainPath": [
"founder",
"asgard",
"odin",
"gleipnir"
"owner",
"mu",
"pirsig"
],
"nodes": [
{
"id": "founder",
"id": "owner",
"lane": "steer",
"col": 1,
"type": "external",
"label": "Founder",
"width": 220,
"sublabel": "approves direction"
"label": "Owners",
"width": 180,
"sublabel": "write the rules, merge"
},
{
"id": "jorm",
"lane": "core",
"col": 0,
"type": "backend",
"label": "Jormungandr",
"width": 220,
"sublabel": "build, check, fix loop"
},
{
"id": "odin",
"lane": "core",
"id": "mu",
"lane": "chart",
"col": 1,
"type": "backend",
"label": "Odin",
"width": 220,
"sublabel": "orchestrator, ygg CLI"
},
{
"id": "gleipnir",
"lane": "core",
"col": 2,
"type": "backend",
"label": "Gleipnir",
"width": 220,
"sublabel": "harness: agents, sandbox"
},
{
"id": "voluspa",
"lane": "realms",
"col": 0,
"type": "database",
"label": "Voluspa",
"width": 220,
"sublabel": "graph library"
"label": "mu",
"width": 180,
"sublabel": "dogma, standards, brain"
},
{
"id": "asgard",
"lane": "realms",
"id": "gramatico",
"lane": "think",
"col": 0,
"type": "backend",
"label": "gramatico",
"width": 180,
"sublabel": "plain pt-BR"
},
{
"id": "pirsig",
"lane": "think",
"col": 1,
"type": "frontend",
"label": "Asgard realm",
"width": 220,
"sublabel": "kickstart"
"label": "pirsig",
"width": 180,
"sublabel": "a second brain"
},
{
"id": "realms",
"lane": "realms",
"id": "alerts",
"lane": "host",
"col": 0,
"type": "backend",
"label": "alerts",
"width": 180,
"sublabel": "official alerts"
},
{
"id": "rax",
"lane": "host",
"col": 1,
"type": "backend",
"label": "rax",
"width": 180,
"sublabel": "agentic runtime"
},
{
"id": "agents",
"lane": "host",
"col": 2,
"type": "frontend",
"label": "Build realms",
"width": 220,
"sublabel": "Midgard, Helheim"
"type": "backend",
"label": "agents",
"width": 180,
"sublabel": "watch and report"
},
{
"id": "products",
"lane": "out",
"id": "nixos",
"lane": "host",
"col": 3,
"type": "database",
"label": "nix-os",
"width": 180,
"sublabel": "the VPS"
},
{
"id": "ihero",
"lane": "play",
"col": 0,
"type": "frontend",
"label": "ihero",
"width": 180,
"sublabel": "music, coming"
},
{
"id": "dojo",
"lane": "play",
"col": 1,
"type": "external",
"label": "Companies and products",
"width": 220,
"sublabel": "lessons feed back"
"type": "frontend",
"label": "dojo",
"width": 180,
"sublabel": "道場, empty so far"
}
],
"edges": [
{
"id": "e1",
"from": "founder",
"to": "asgard",
"label": "approves"
"from": "owner",
"to": "mu",
"label": "approve"
},
{
"id": "e2",
"from": "asgard",
"to": "odin",
"label": "recipe, later"
"from": "mu",
"to": "pirsig",
"label": "managed by"
},
{
"id": "e3",
"from": "realms",
"to": "odin",
"label": "recipes"
"from": "agents",
"to": "nixos",
"label": "watch"
},
{
"id": "e4",
"from": "voluspa",
"to": "odin",
"label": "graphs"
},
{
"id": "e5",
"from": "odin",
"to": "jorm"
},
{
"id": "e6",
"from": "odin",
"to": "gleipnir"
},
{
"id": "e7",
"from": "realms",
"to": "products",
"label": "builds and verifies"
"from": "rax",
"to": "agents",
"label": "runs"
}
]
}
-104
View File
@@ -1,104 +0,0 @@
{
"schema_version": 2,
"diagram_type": "workflow",
"meta": {
"title": "The portfolio: one factory, two kinds of realm",
"locale": "en",
"quality_profile": "showcase",
"legend": {
"mode": "hidden"
},
"output": "piabrota-portfolio.html"
},
"lanes": [
{
"id": "steer",
"label": "Humans steer"
},
{
"id": "factory",
"label": "Yggdrasil"
},
{
"id": "out",
"label": "A company it makes"
}
],
"mainPath": [
"founder",
"asgard",
"company"
],
"nodes": [
{
"id": "founder",
"lane": "steer",
"col": 0,
"type": "external",
"label": "Founder",
"width": 220,
"sublabel": "approves direction"
},
{
"id": "asgard",
"lane": "factory",
"col": 0,
"type": "frontend",
"label": "Asgard realm",
"width": 220,
"sublabel": "kickstart, tier 0"
},
{
"id": "build",
"lane": "factory",
"col": 1,
"type": "backend",
"label": "Other realms",
"width": 220,
"sublabel": "web and backend in v0"
},
{
"id": "company",
"lane": "out",
"col": 0,
"type": "external",
"label": "photografy",
"width": 220,
"sublabel": "a company"
},
{
"id": "gallery",
"lane": "out",
"col": 1,
"type": "frontend",
"label": "client gallery",
"width": 220,
"sublabel": "a product"
}
],
"edges": [
{
"id": "e1",
"from": "founder",
"to": "asgard"
},
{
"id": "e2",
"from": "asgard",
"to": "build",
"label": "sets direction"
},
{
"id": "e3",
"from": "asgard",
"to": "company",
"label": "kickstarts"
},
{
"id": "e4",
"from": "build",
"to": "gallery",
"label": "builds and verifies"
}
]
}
+21
View File
@@ -0,0 +1,21 @@
# Drawings
## `mu.svg`
む (*mu*), in its three strokes, 2026. The Nix files in `drawings/` write it in two formats from one
geometry, as [piabrota/nix-os](https://github.com/piabrota/nix-os/tree/6d636be2c4552381d6427d9b506e2a33dc3c1005/drawings) writes its own:
| File | What it is |
| --- | --- |
| `mu.svg` | The README drawing |
| `mu.desmos.json` | The same drawing as a Desmos graph state |
Run `scripts/drawing.sh` to write both. `nix flake check` fails if a drawing test fails, or if the
committed files are not its output. The pen is `drawings/pen.nix`, copied from nix-os; the strokes are
`drawings/mu.nix`.
## `eye.svg`
The piabrota logo, the mark [piabrota.art](https://piabrota.art) shows: an open green eye on red. The site
defines it in code (`eye` in piabrota/nix-os, `site/src/piabrota_site/parts.gleam`), so `drawings/eye.nix`
holds the same shapes and colours. Change it in nix-os first.
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200" role="img" aria-label="The piabrota logo: an open green eye on red">
<rect width="100" height="100" rx="22" fill="#BC2318"/>
<path d="M12 50 Q50 18 88 50 Q50 82 12 50Z" fill="#F7F3EA"/>
<circle cx="50" cy="50" r="14" fill="#2E9E4F"/>
<circle cx="50" cy="50" r="6" fill="#0B0D12"/>
</svg>

After

Width:  |  Height:  |  Size: 383 B

File diff suppressed because it is too large. Load diff
+99
View File
@@ -0,0 +1,99 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240" width="240" height="240" role="img" aria-label="む (mu) brushed in its three strokes">
<title>む (mu) brushed in its three strokes</title>
<desc>Drawn from the Desmos expressions of mu.desmos.json: cubic Béziers through hand-placed points, each piece at its brush width.</desc>
<style>.l{fill:none;stroke:#1f2328;stroke-linecap:round;stroke-linejoin:round}.d{fill:#1f2328;stroke:none}@media (prefers-color-scheme:dark){.l{stroke:#e6edf3}.d{fill:#e6edf3}}</style>
<g class="l">
<path d="M45.2 78.2 C45.75 78.108 46.3 77.985 46.953 77.836" stroke-width="10.78"/>
<path d="M46.953 77.836 C47.606 77.687 48.363 77.513 49.325 77.32" stroke-width="10.34"/>
<path d="M49.325 77.32 C50.287 77.128 51.456 76.917 52.934 76.694" stroke-width="9.9"/>
<path d="M52.934 76.694 C54.412 76.472 56.2 76.238 58.4 76" stroke-width="9.46"/>
<path d="M58.4 76 C60.6 75.762 63.442 75.491 66.65 75.203" stroke-width="8.965"/>
<path d="M66.65 75.203 C69.858 74.914 73.433 74.607 77.1 74.295" stroke-width="8.415"/>
<path d="M77.1 74.295 C80.767 73.983 84.525 73.667 88.1 73.36" stroke-width="7.865"/>
<path d="M88.1 73.36 C91.675 73.053 95.067 72.755 98 72.48" stroke-width="7.315"/>
<path d="M98 72.48 C100.933 72.205 103.89 71.902 106.783 71.597" stroke-width="7.15"/>
<path d="M106.783 71.597 C109.676 71.291 112.506 70.981 115.188 70.693" stroke-width="7.37"/>
<path d="M115.188 70.693 C117.869 70.404 120.401 70.136 122.698 69.912" stroke-width="7.59"/>
<path d="M122.698 69.912 C124.996 69.689 127.058 69.51 128.8 69.4" stroke-width="7.81"/>
<path d="M128.8 69.4 C130.542 69.29 131.985 69.258 133.2 69.273" stroke-width="8.305"/>
<path d="M133.2 69.273 C134.415 69.288 135.4 69.35 136.225 69.428" stroke-width="9.075"/>
<path d="M136.225 69.428 C137.05 69.505 137.715 69.599 138.288 69.678" stroke-width="9.845"/>
<path d="M138.288 69.678 C138.86 69.758 139.342 69.822 139.8 69.84" stroke-width="10.615"/>
<path d="M91.4 34.2 C91.455 34.842 91.556 35.598 91.678 36.503" stroke-width="13.035"/>
<path d="M91.678 36.503 C91.801 37.408 91.945 38.463 92.087 39.7" stroke-width="12.705"/>
<path d="M92.087 39.7 C92.23 40.937 92.369 42.358 92.483 43.997" stroke-width="12.375"/>
<path d="M92.483 43.997 C92.596 45.635 92.683 47.492 92.72 49.6" stroke-width="12.045"/>
<path d="M92.72 49.6 C92.757 51.708 92.761 54.252 92.744 57.059" stroke-width="11.66"/>
<path d="M92.744 57.059 C92.727 59.867 92.688 62.938 92.638 66.1" stroke-width="11.22"/>
<path d="M92.638 66.1 C92.587 69.263 92.525 72.517 92.462 75.691" stroke-width="10.78"/>
<path d="M92.462 75.691 C92.399 78.865 92.335 81.958 92.28 84.8" stroke-width="10.34"/>
<path d="M92.28 84.8 C92.225 87.642 92.243 90.63 92.277 93.638" stroke-width="10.065"/>
<path d="M92.277 93.638 C92.31 96.646 92.358 99.673 92.362 102.592" stroke-width="9.955"/>
<path d="M92.362 102.592 C92.367 105.512 92.328 108.324 92.187 110.901" stroke-width="9.845"/>
<path d="M92.187 110.901 C92.046 113.478 91.803 115.82 91.4 117.8" stroke-width="9.735"/>
<path d="M91.4 117.8 C90.997 119.78 90.534 121.508 89.994 123.028" stroke-width="9.515"/>
<path d="M89.994 123.028 C89.454 124.549 88.838 125.862 88.128 127.012" stroke-width="9.185"/>
<path d="M88.128 127.012 C87.417 128.163 86.613 129.151 85.697 130.02" stroke-width="8.855"/>
<path d="M85.697 130.02 C84.782 130.89 83.755 131.642 82.6 132.32" stroke-width="8.525"/>
<path d="M82.6 132.32 C81.445 132.998 79.923 133.585 78.231 134.049" stroke-width="8.195"/>
<path d="M78.231 134.049 C76.539 134.513 74.675 134.855 72.837 135.043" stroke-width="7.865"/>
<path d="M72.837 135.043 C71 135.23 69.187 135.265 67.595 135.115" stroke-width="7.535"/>
<path d="M67.595 135.115 C66.004 134.965 64.633 134.63 63.68 134.08" stroke-width="7.205"/>
<path d="M63.68 134.08 C62.727 133.53 61.883 132.567 61.184 131.371" stroke-width="6.985"/>
<path d="M61.184 131.371 C60.485 130.175 59.931 128.745 59.555 127.26" stroke-width="6.875"/>
<path d="M59.555 127.26 C59.179 125.775 58.982 124.235 58.998 122.819" stroke-width="6.765"/>
<path d="M58.998 122.819 C59.014 121.403 59.243 120.11 59.72 119.12" stroke-width="6.655"/>
<path d="M59.72 119.12 C60.197 118.13 61.068 117.062 62.188 116.023" stroke-width="6.655"/>
<path d="M62.188 116.023 C63.309 114.984 64.679 113.973 66.155 113.098" stroke-width="6.765"/>
<path d="M66.155 113.098 C67.631 112.222 69.212 111.482 70.754 110.983" stroke-width="6.875"/>
<path d="M70.754 110.983 C72.297 110.485 73.8 110.228 75.12 110.32" stroke-width="6.985"/>
<path d="M75.12 110.32 C76.44 110.412 77.911 110.815 79.427 111.451" stroke-width="7.205"/>
<path d="M79.427 111.451 C80.943 112.087 82.504 112.955 84.003 113.978" stroke-width="7.535"/>
<path d="M84.003 113.978 C85.501 115 86.938 116.175 88.207 117.425" stroke-width="7.865"/>
<path d="M88.207 117.425 C89.475 118.675 90.575 120 91.4 121.32" stroke-width="8.195"/>
<path d="M91.4 121.32 C92.225 122.64 92.835 124.102 93.291 125.675" stroke-width="8.58"/>
<path d="M93.291 125.675 C93.747 127.249 94.049 128.933 94.26 130.698" stroke-width="9.02"/>
<path d="M94.26 130.698 C94.471 132.462 94.59 134.307 94.679 136.201" stroke-width="9.46"/>
<path d="M94.679 136.201 C94.769 138.095 94.828 140.038 94.92 142" stroke-width="9.9"/>
<path d="M94.92 142 C95.012 143.962 94.897 146.065 94.693 148.249" stroke-width="10.34"/>
<path d="M94.693 148.249 C94.489 150.433 94.196 152.698 93.93 154.98" stroke-width="10.78"/>
<path d="M93.93 154.98 C93.664 157.263 93.426 159.563 93.332 161.821" stroke-width="11.22"/>
<path d="M93.332 161.821 C93.238 164.078 93.288 166.292 93.6 168.4" stroke-width="11.66"/>
<path d="M93.6 168.4 C93.912 170.508 94.274 172.708 94.728 174.914" stroke-width="11.935"/>
<path d="M94.728 174.914 C95.181 177.12 95.727 179.331 96.405 181.463" stroke-width="12.045"/>
<path d="M96.405 181.463 C97.083 183.594 97.895 185.645 98.88 187.53" stroke-width="12.155"/>
<path d="M98.88 187.53 C99.865 189.415 101.025 191.133 102.4 192.6" stroke-width="12.265"/>
<path d="M102.4 192.6 C103.775 194.067 105.402 195.419 107.213 196.639" stroke-width="12.155"/>
<path d="M107.213 196.639 C109.023 197.859 111.017 198.948 113.125 199.888" stroke-width="11.825"/>
<path d="M113.125 199.888 C115.233 200.827 117.456 201.618 119.725 202.242" stroke-width="11.495"/>
<path d="M119.725 202.242 C121.994 202.867 124.308 203.325 126.6 203.6" stroke-width="11.165"/>
<path d="M126.6 203.6 C128.892 203.875 131.435 204.013 134.094 203.995" stroke-width="10.78"/>
<path d="M134.094 203.995 C136.752 203.978 139.525 203.806 142.275 203.463" stroke-width="10.34"/>
<path d="M142.275 203.463 C145.025 203.119 147.752 202.603 150.319 201.898" stroke-width="9.9"/>
<path d="M150.319 201.898 C152.885 201.194 155.292 200.3 157.4 199.2" stroke-width="9.46"/>
<path d="M157.4 199.2 C159.508 198.1 161.516 196.702 163.412 195.092" stroke-width="9.075"/>
<path d="M163.412 195.092 C165.309 193.482 167.094 191.66 168.758 189.713" stroke-width="8.745"/>
<path d="M168.758 189.713 C170.421 187.765 171.964 185.691 173.374 183.577" stroke-width="8.415"/>
<path d="M173.374 183.577 C174.785 181.463 176.063 179.308 177.2 177.2" stroke-width="8.085"/>
<path d="M177.2 177.2 C178.337 175.092 179.441 172.479 180.442 169.689" stroke-width="7.755"/>
<path d="M180.442 169.689 C181.442 166.899 182.338 163.931 183.058 161.113" stroke-width="7.425"/>
<path d="M183.058 161.113 C183.777 158.294 184.32 155.624 184.615 153.43" stroke-width="7.095"/>
<path d="M184.615 153.43 C184.909 151.235 184.955 149.517 184.68 148.6" stroke-width="6.765"/>
<path d="M184.68 148.6 C184.405 147.683 183.534 147.569 182.346 147.93" stroke-width="6.16"/>
<path d="M182.346 147.93 C181.158 148.291 179.652 149.127 178.108 150.112" stroke-width="5.28"/>
<path d="M178.108 150.112 C176.563 151.098 174.979 152.232 173.635 153.189" stroke-width="4.4"/>
<path d="M173.635 153.189 C172.291 154.146 171.187 154.925 170.6 155.2" stroke-width="3.52"/>
<path d="M164 67.2 C164.55 67.658 165.398 68.323 166.423 69.125" stroke-width="9.185"/>
<path d="M166.423 69.125 C167.449 69.927 168.652 70.867 169.913 71.875" stroke-width="9.955"/>
<path d="M169.913 71.875 C171.173 72.883 172.491 73.96 173.745 75.038" stroke-width="10.725"/>
<path d="M173.745 75.038 C175 76.115 176.192 77.192 177.2 78.2" stroke-width="11.495"/>
<path d="M177.2 78.2 C178.208 79.208 179.24 80.308 180.259 81.448" stroke-width="12.1"/>
<path d="M180.259 81.448 C181.279 82.589 182.288 83.769 183.25 84.938" stroke-width="12.54"/>
<path d="M183.25 84.938 C184.213 86.106 185.129 87.264 185.966 88.358" stroke-width="12.98"/>
<path d="M185.966 88.358 C186.802 89.452 187.558 90.483 188.2 91.4" stroke-width="13.42"/>
<path d="M188.2 91.4 C188.842 92.317 189.392 93.233 189.867 94.116" stroke-width="12.87"/>
<path d="M189.867 94.116 C190.343 94.998 190.744 95.846 191.088 96.625" stroke-width="11.33"/>
<path d="M191.088 96.625 C191.431 97.404 191.718 98.115 191.964 98.722" stroke-width="9.79"/>
<path d="M191.964 98.722 C192.21 99.329 192.417 99.833 192.6 100.2" stroke-width="8.25"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

+63
View File
@@ -0,0 +1,63 @@
# The README drawing, む, in pure Nix: `svg`, `desmos` and `checkSvg` are the files' text,
# `failures` the tests that failed (lib.runTests), empty when all pass.
{ lib }:
let
pen = import ./pen.nix { inherit lib; };
mu = import ./mu.nix { inherit lib pen; };
near = a: b: (if a < b then b - a else a - b) < 1.0e-9;
bz = [ [ 0.0 0.0 ] [ 10.0 30.0 ] [ 40.0 (-10.0) ] [ 50.0 20.0 ] ];
inherit (builtins) elemAt;
first = s: elemAt s 0;
last = s: elemAt s (builtins.length s - 1);
stroke = elemAt mu.strokes;
col = k: p: elemAt p k;
in
{
inherit (mu.drawing) svg desmos checkSvg;
eye = import ./eye.nix;
failures = lib.runTests {
testNumbersAreShort = {
expr = map pen.num [ 12.0 (-3.5) 0.1234 (-0.0001) ];
expected = [ "12" "-3.5" "0.123" "0" ];
};
testAPolynomialReadsBack = {
expr = let s = pen.poly [ 12.5 (-3.0) 0.0 0.25 ]; in [ s (pen.parsePoly s) ];
expected = [ "12.5-3t+0.25t^{3}" [ 12.5 (-3.0) 0.0 0.25 ] ];
};
testAPartIsTheSameCurve = {
expr = builtins.all
(k:
let
s = k / 4.0;
p = pen.at (pen.part bz 0.25 0.75) s;
q = pen.at bz (0.5 * s + 0.25);
in
near (col 0 p) (col 0 q) && near (col 1 p) (col 1 q))
(lib.range 0 4);
expected = true;
};
testThePowerFormIsTheBezier = {
# Midpoint of a cubic Bézier: (p0 + 3p1 + 3p2 + p3) / 8.
expr = let cx = elemAt (pen.coeffs bz) 0; in
near (pen.evalPoly cx 0.5) 25.0 && near (pen.evalPoly cx 1.0) 50.0;
expected = true;
};
testMuHasItsThreeStrokesInOrder = {
expr = [
(builtins.length mu.strokes)
# the second stroke starts above the first and ends below it
(col 1 (first (stroke 1)) < col 1 (first (stroke 0)))
(col 1 (last (stroke 1)) > col 1 (last (stroke 0)))
# the dot sits on the right of the second stroke's start
(col 0 (first (stroke 2)) > col 0 (first (stroke 1)))
];
expected = [ 3 true true true ];
};
# Every Desmos expression, read back from its LaTeX, stays within 0.01 of its line.
testTheDesmosFileIsTheDrawing = {
expr = mu.drawing.worstSquared < 0.01 * 0.01;
expected = true;
};
};
}
+10
View File
@@ -0,0 +1,10 @@
# The piabrota logo, the mark piabrota.art shows: an open green eye on red. The shapes and colours are
# those of `eye` in piabrota/nix-os, site/src/piabrota_site/parts.gleam at 6d636be. Change it there first.
''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200" height="200" role="img" aria-label="The piabrota logo: an open green eye on red">
<rect width="100" height="100" rx="22" fill="#BC2318"/>
<path d="M12 50 Q50 18 88 50 Q50 82 12 50Z" fill="#F7F3EA"/>
<circle cx="50" cy="50" r="14" fill="#2E9E4F"/>
<circle cx="50" cy="50" r="6" fill="#0B0D12"/>
</svg>
''
+71
View File
@@ -0,0 +1,71 @@
# The mu drawing: む (*mu*), the hiragana, brushed in its three strokes, in the standard order.
# The shape of piabrota/nix-os' drawing: pirsig's logo is the kanji 無 and nix-os' is 无; this
# repository writes the same sound with no meaning of its own, in kana.
#
# Each stroke is a brush line through hand-placed points with a width at each point: the first
# stops firmly, the second comes down, ties its small loop on the left, runs along the bottom and
# rises, and the third is a short falling dot.
{ lib, pen }:
let
# The three strokes of む, in writing order, in a 0–100 box: [x y brush width at that point].
strokes = [
# 1 the short horizontal, rising a little, stopped at the end
[
[ 14.0 31.0 5.0 ]
[ 20.0 30.0 4.2 ]
[ 38.0 28.4 3.2 ]
[ 52.0 27.0 3.6 ]
[ 57.0 27.2 5.0 ]
]
# 2 down, the small loop to the left, on down, along the bottom, and up to the right
[
[ 35.0 11.0 6.0 ]
[ 35.6 18.0 5.4 ]
[ 35.4 34.0 4.6 ]
[ 35.0 49.0 4.4 ]
[ 31.0 55.6 3.8 ]
[ 22.4 56.4 3.2 ]
[ 20.6 49.6 3.0 ]
[ 27.6 45.6 3.2 ]
[ 35.0 50.6 3.8 ]
[ 36.6 60.0 4.6 ]
[ 36.0 72.0 5.4 ]
[ 40.0 83.0 5.6 ]
[ 51.0 88.0 5.0 ]
[ 65.0 86.0 4.2 ]
[ 74.0 76.0 3.6 ]
[ 77.4 63.0 3.0 ]
[ 71.0 66.0 1.4 ]
]
# 3 the short falling dot, on the upper right
[
[ 68.0 26.0 4.0 ]
[ 74.0 31.0 5.4 ]
[ 79.0 37.0 6.2 ]
[ 81.0 41.0 3.4 ]
]
];
# The canvas, square, with the kana in its middle: the 0–100 box scaled by `scale` about its
# point (48, 50). The widths of `strokes` are times `weight`, how heavy the brush is.
side = 240.0;
scale = 2.2;
weight = 2.2;
place = p: [
(pen.fma (builtins.elemAt p 0 - 48.0) scale (side / 2.0))
(pen.fma (builtins.elemAt p 1 - 50.0) scale (side / 2.0))
];
in
{
inherit strokes;
drawing = pen.drawing {
w = side;
h = side;
label = "む (mu) brushed in its three strokes";
desc = "Drawn from the Desmos expressions of mu.desmos.json: cubic Béziers through hand-placed points, each piece at its brush width.";
marks = lib.concatMap
(s: pen.brush (map place s) (map (p: builtins.elemAt p 2 * weight) s))
strokes;
};
}
+333
View File
@@ -0,0 +1,333 @@
# A pen for Desmos line art, in pure Nix: pirsig's pen (crates/pirsig-drawings, at 450e4da)
# Copied from piabrota/nix-os (drawings/pen.nix at 6d636be), MPL-2.0.
# ported from Rust.
#
# A stroke is a list of points. The pen runs a Catmull-Rom spline through them, so the line is
# smooth and passes through every point. Each piece of the spline is a cubic Bézier, and each
# Bézier is one Desmos parametric expression, `(a+bt+ct^2+dt^3, …)` for `0 ≤ t ≤ 1`.
#
# The SVG has y down and Desmos has y up: a Desmos y is `H - y` of the SVG.
# Nix has no fused multiply-add and no square root: `fma` stands in for Rust's `mul_add`, so the
# numbers come out as the Rust pen's did, and the check compares squared distances.
{ lib }:
let
inherit (builtins) concatStringsSep elemAt floor genList length;
# The ink of the drawing, light and dark, as in picasso's drawings.
ink = "#1f2328";
inkDark = "#e6edf3";
# The blue of the check render, the same as in piabrota/alerts, and the orange of its Desmos layer.
blue = "#1682D4";
orange = "#FF4F00";
x = p: elemAt p 0;
y = p: elemAt p 1;
# Rust's f64::round, half away from zero, as an integer.
round = v: if v < 0 then -(floor (0.5 - v)) else floor (v + 0.5);
abs = v: if v < 0 then -v else v;
# a * b + c as one rounding, as Rust's f64::mul_add: the exact product as a sum of two floats
# (Dekker's split), then a compensated sum (Ogita, Rump and Oishi, 2005). Rounding a * b first
# moves some numbers of the drawing by 0.001.
fma = a: b: c:
let
split = v:
let t = 134217729.0 * v; hi = t - (t - v);
in [ hi (v - hi) ];
sa = split a;
sb = split b;
p = a * b;
e = elemAt sa 0 * elemAt sb 0 - p + elemAt sa 0 * elemAt sb 1 + elemAt sa 1 * elemAt sb 0
+ elemAt sa 1 * elemAt sb 1;
s = p + c;
z = s - p;
err = p - (s - z) + (c - z);
in
s + (err + e);
# The integer `a` with its last `d` digits as decimals, after a minus sign when `neg`.
decimals = d: neg: a:
let p = lib.foldl' (acc: _: acc * 10) 1 (genList (_: null) d);
in "${lib.optionalString neg "-"}${toString (a / p)}.${lib.fixedWidthNumber d (a - a / p * p)}";
# `v` with one decimal, as Rust's `{:.1}`: the nearest of the exact value, a tie to even.
tenths = v:
let
f = floor (v * 10.0);
r = fma v 10.0 (-f * 1.0);
n = if r > 0.5 || (r == 0.5 && lib.mod f 2 != 0) then f + 1 else f;
in
decimals 1 (v < 0) (abs n);
# A number with at most three decimals, without trailing zeros: `12`, `-3.5`, `0.125`.
num = v:
let
n = round (v * 1000.0);
m = builtins.match "(-?[0-9]+)\\.([0-9]*[1-9])?0*" (decimals 3 (n < 0) (abs n));
in
if elemAt m 1 == null then elemAt m 0 else "${elemAt m 0}.${elemAt m 1}";
# `a+bt+ct^{2}+dt^{3}`, skipping the terms that round to zero.
poly = c:
num (elemAt c 0) + concatStringsSep "" (genList
(i:
let
k = i + 1;
s = num (elemAt c k);
pow = if k == 1 then "t" else "t^{${toString k}}";
in
lib.optionalString (s != "0") "${lib.optionalString (!lib.hasPrefix "-" s) "+"}${s}${pow}")
3);
# The power form `a + bt + ct² + dt³` of each axis of a Bézier: [[a b c d] [a b c d]].
coeffs = bz:
let
f = axis:
let
a = axis (elemAt bz 0);
b = axis (elemAt bz 1);
c = axis (elemAt bz 2);
d = axis (elemAt bz 3);
in
[ a (3.0 * (b - a)) (3.0 * (fma 2.0 (-b) a + c)) (fma 3.0 (b - c) (d - a)) ];
in
[ (f x) (f y) ];
# The point of a Bézier at `t`.
at = bz: t:
let
u = 1.0 - t;
f = axis:
fma (u * u * u) (axis (elemAt bz 0)) (fma (3.0 * u * u * t) (axis (elemAt bz 1))
(fma (3.0 * u * t * t) (axis (elemAt bz 2)) (t * t * t * axis (elemAt bz 3))));
in
[ (f x) (f y) ];
# The same curve between `t0` and `t1`, as a Bézier of its own.
part = bz: t0: t1:
let
h = t1 - t0;
# derivative at t, for the control points of the piece
deriv = t:
let
u = 1.0 - t;
g = axis:
let
a = axis (elemAt bz 0);
b = axis (elemAt bz 1);
c = axis (elemAt bz 2);
e = axis (elemAt bz 3);
in
3.0 * fma (u * u) (b - a) (fma (2.0 * u * t) (c - b) (t * t * (e - c)));
in
[ (g x) (g y) ];
a = at bz t0;
b = at bz t1;
da = deriv t0;
db = deriv t1;
in
[
a
[ (fma (x da) (h / 3.0) (x a)) (fma (y da) (h / 3.0) (y a)) ]
[ (fma (x db) (-h / 3.0) (x b)) (fma (y db) (-h / 3.0) (y b)) ]
b
];
# The Béziers of the open Catmull-Rom spline through `pts`, held at its ends.
spline = pts:
let
n = length pts;
get = i: elemAt pts (lib.max 0 (lib.min (n - 1) i));
in
genList
(i:
let
p0 = get (i - 1);
p1 = get i;
p2 = get (i + 1);
p3 = get (i + 2);
in
[
p1
[ (x p1 + (x p2 - x p0) / 6.0) (y p1 + (y p2 - y p0) / 6.0) ]
[ (x p2 - (x p3 - x p1) / 6.0) (y p2 - (y p3 - y p1) / 6.0) ]
p2
])
(n - 1);
# Pieces each segment of a brush stroke is cut into, so its width changes smoothly.
pieces = 4;
# A brush stroke through `pts`: the smooth line of `spline`, whose width follows `widths` (one
# per point) as a brush presses down and lifts. Each segment is cut into `pieces` Béziers, each
# a mark { bezier; width; } drawn at the width of its middle.
brush = pts: widths:
assert length pts == length widths;
lib.concatLists (lib.imap0
(i: bz: genList
(j:
let
t0 = j * 1.0 / pieces;
t1 = (j + 1) * 1.0 / pieces;
mid = (t0 + t1) / 2.0;
w0 = elemAt widths i;
in
{
bezier = part bz t0 t1;
width = fma (elemAt widths (i + 1) - w0) mid w0;
})
pieces)
(spline pts));
# Pretty JSON as serde_json writes it: two spaces, sorted keys, a float with its `.0`.
json = indent: v:
let next = indent + " ";
in
if builtins.isAttrs v then
"{\n${concatStringsSep ",\n" (map (k: "${next}${builtins.toJSON k}: ${json next v.${k}}") (builtins.attrNames v))}\n${indent}}"
else if builtins.isList v then
"[\n${concatStringsSep ",\n" (map (e: next + json next e) v)}\n${indent}]"
else if builtins.isFloat v then
(if floor v == v then "${toString (floor v)}.0" else throw "json: ${toString v} is not whole")
else builtins.toJSON v;
# The two coordinates of `\left(x,y\right)`, each as polynomial coefficients by power of t.
parsePair = latex:
let
m = builtins.match "\\\\left\\(([^,]*),([^,]*)\\\\right\\)" latex;
in
if m == null then throw "cannot read ${latex}" else map parsePoly m;
# `12.5-3t+0.25t^{2}` → [12.5 -3 0.25 0].
parsePoly = s:
let
parts = builtins.split "([+-]?[^+-]+)" s;
read = term:
let m = builtins.match "\\+?(-?[0-9.]+)(t(\\^\\{([0-9])})?)?" term;
in
if m == null then throw "cannot read the term ${term} of ${s}"
else {
c = builtins.fromJSON (elemAt m 0) * 1.0;
k = if elemAt m 1 == null then 0 else if elemAt m 3 == null then 1 else lib.toInt (elemAt m 3);
};
terms = map (m: read (elemAt m 0)) (builtins.filter builtins.isList parts);
in
assert builtins.all (p: builtins.isList p || p == "") parts;
genList (k: lib.foldl' (acc: r: if r.k == k then acc + r.c else acc) 0.0 terms) 4;
evalPoly = c: t: lib.foldr (v: acc: fma acc t v) 0.0 c;
in
{
inherit fma num poly coeffs at part evalPoly parsePoly brush tenths;
# A finished drawing: its canvas `w` × `h`, its label and description, and its marks.
drawing = { w, h, label, desc, marks }:
let
expressions = lib.imap1
(i: mark:
let
c = coeffs mark.bezier;
cx = elemAt c 0;
cy = elemAt c 1;
px = poly cx;
py = poly ([ (h - elemAt cy 0) ] ++ map (v: -v) (lib.drop 1 cy));
in
{
type = "expression";
id = toString i;
color = blue;
latex = "\\left(${px},${py}\\right)";
parametricDomain = { min = "0"; max = "1"; };
lineWidth = num mark.width;
})
marks;
# The geometry as SVG paths, one per mark.
shapes = map
(mark:
let
b = mark.bezier;
pt = p: "${num (x p)} ${num (y p)}";
in
"<path d=\"M${pt (elemAt b 0)} C${pt (elemAt b 1)} ${pt (elemAt b 2)} ${pt (elemAt b 3)}\" stroke-width=\"${num mark.width}\"/>")
marks;
sw = num w;
sh = num h;
in
{
# The drawing as a Desmos graph state (`version` 11).
desmos = json ""
{
version = 11;
graph = {
viewport = { xmin = 0; xmax = w; ymin = 0; ymax = h; };
showGrid = false;
showXAxis = false;
showYAxis = false;
};
expressions.list = expressions;
} + "\n";
# The drawing as SVG, in ink, as picasso draws: near black on light pages, near
# white on dark ones (`prefers-color-scheme`).
svg = ''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${sw} ${sh}" width="${sw}" height="${sh}" role="img" aria-label="${label}">
<title>${label}</title>
<desc>${desc}</desc>
<style>.l{fill:none;stroke:${ink};stroke-linecap:round;stroke-linejoin:round}.d{fill:${ink};stroke:none}@media (prefers-color-scheme:dark){.l{stroke:${inkDark}}.d{fill:${inkDark}}}</style>
<g class="l">
${concatStringsSep "\n " shapes}
</g>
</svg>
'';
# The check render: the geometry in blue and, on top, each Desmos expression read back from
# its LaTeX and sampled in orange. Where the two agree, the orange line runs inside the blue.
checkSvg =
let
orangeLines = map
(e:
let
f = parsePair e.latex;
pts = genList
(i:
let t = i / 24.0;
in "${tenths (evalPoly (elemAt f 0) t)},${tenths (h - evalPoly (elemAt f 1) t)}")
25;
lw = builtins.fromJSON e.lineWidth * 1.0;
in
"<polyline points=\"${concatStringsSep " " pts}\" stroke-width=\"${num (lib.min (0.4 * lw) 0.8)}\"/>")
expressions;
in
''
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${sw} ${sh}" width="${sw}" height="${sh}" role="img" aria-label="${label}, with its Desmos expressions over it">
<g fill="none" stroke="${blue}" stroke-linecap="round" stroke-linejoin="round">
${concatStringsSep "\n " shapes}
</g>
<g fill="none" stroke="${orange}" stroke-linecap="round" stroke-linejoin="round">
${concatStringsSep "\n " orangeLines}
</g>
</svg>
'';
# The square of how far, at most, any Desmos expression strays from the line it stands for:
# each one is read back from its LaTeX and compared with its Bézier at eleven points.
worstSquared = lib.foldl' lib.max 0.0 (lib.zipListsWith
(mark: e:
let f = parsePair e.latex;
in lib.foldl' lib.max 0.0 (genList
(i:
let
t = i / 10.0;
p = at mark.bezier t;
dx = evalPoly (elemAt f 0) t - x p;
dy = h - evalPoly (elemAt f 1) t - y p;
in
dx * dx + dy * dy)
11))
marks
expressions);
};
}
Generated
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1793294725,
"narHash": "sha256-loLMnbbS4KhmG2ln9EY6f0YMNCA273Yx02oWYQ9IMeE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6f06d204d8f2d8761d9da78778745974a3216381",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-26.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+38
View File
@@ -0,0 +1,38 @@
{
description = "mu, the piabrota company chart: its drawings, in pure Nix";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ];
each = nixpkgs.lib.genAttrs systems;
drawing = import ./drawings { inherit (nixpkgs) lib; };
in
{
# The README drawings: eye.svg, mu.svg, mu.desmos.json and mu-check.svg.
packages = each (system:
let pkgs = nixpkgs.legacyPackages.${system}; in {
mu-art = pkgs.linkFarm "mu-art" [
{ name = "eye.svg"; path = pkgs.writeText "eye.svg" drawing.eye; }
{ name = "mu.svg"; path = pkgs.writeText "mu.svg" drawing.svg; }
{ name = "mu.desmos.json"; path = pkgs.writeText "mu.desmos.json" drawing.desmos; }
{ name = "mu-check.svg"; path = pkgs.writeText "mu-check.svg" drawing.checkSvg; }
];
});
# The drawing's tests pass and the committed files are its output (scripts/drawing.sh).
checks = each (system:
let pkgs = nixpkgs.legacyPackages.${system}; in {
drawing = pkgs.runCommand "mu-art-check" { } ''
${pkgs.lib.concatMapStrings (f: "echo 'failed: ${f.name}' >&2\n") drawing.failures}
${pkgs.lib.optionalString (drawing.failures != [ ]) "exit 1"}
art=${self.packages.${system}.mu-art}
diff -u ${./docs/drawings/eye.svg} $art/eye.svg || { echo 'run scripts/drawing.sh' >&2; exit 1; }
diff -u ${./docs/drawings/mu.svg} $art/mu.svg || { echo 'run scripts/drawing.sh' >&2; exit 1; }
diff -u ${./docs/drawings/mu.desmos.json} $art/mu.desmos.json || { echo 'run scripts/drawing.sh' >&2; exit 1; }
touch $out
'';
});
};
}
+1
Submodule products/agents added at 70f5b16e4b.
+1
Submodule products/alerts added at 40d244f5e8.
Submodule products/asgard deleted from 3e614b4e7a.
Submodule
+1
Submodule products/dojo added at 5196fbb8d8.
Submodule products/gramatico added at d57371af30.
+1
Submodule products/ihero added at ed8dfa1e90.
+1
Submodule products/nix-os added at 6d636be2c4.
+1
Submodule products/pirsig added at b7dd1da2ac.
Submodule
+1
Submodule products/rax added at b87c790db8.
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Write the README drawings, docs/drawings/eye.svg, mu.svg and its Desmos state, from drawings/*.nix.
# nix flake check then fails if a drawing test fails or the committed files are not this output.
# drawing.sh
set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
art="$(nix --extra-experimental-features 'nix-command flakes' build .#mu-art --no-link --print-out-paths)"
cat "$art/eye.svg" >docs/drawings/eye.svg
cat "$art/mu.svg" >docs/drawings/mu.svg
cat "$art/mu.desmos.json" >docs/drawings/mu.desmos.json
+25 -52
View File
@@ -2,14 +2,14 @@
# Private repos are never listed, only counted: this repository is public.
[meta]
as_of = "2026-11-01"
private_count = 2
private_count = 0
[[umbrella]]
[[chart]]
name = "mu"
licence = "CC BY 4.0, AGPL-3.0, MPL-2.0"
what = "The company umbrella: dogma, charter, standards, journal, brand and the scripts every project inherits."
what = "The company chart: dogma, charter, standards, journal, brand and the scripts every project inherits."
[[umbrella]]
[[chart]]
name = ".github"
licence = "MPL-2.0"
what = "The org's profile, with the project table, the fabric figure and the funding links."
@@ -57,25 +57,39 @@ what = "The NixOS configuration of the small VPS that serves piabrota.art. A mer
role = "Hosts the site, rax, the agents and PGX."
[[project]]
name = "ihoje"
lane = "archived"
licence = "no licence file"
what = "A Rust event scraper with anime-inspired module names. Archived and no longer maintained."
role = "None."
name = "ihero"
lane = "play"
licence = "MPL-2.0"
what = "A FOSS music player and game, in Rust. Coming: the repo holds only its licence."
role = "None yet."
[[project]]
name = "dojo"
lane = "not set"
licence = "MPL-2.0"
what = "道場. Empty so far: a licence and a title."
role = "None yet."
[[fork]]
name = "yggdrasil"
upstream = "ouroboric-dev/yggdrasil"
group = "The factory"
sync = "even"
why = "Submodule of this repo: the agentic factory."
why = "The agentic factory this repo inherited its method from."
[[fork]]
name = "asgard"
upstream = "ouroboric-dev/asgard"
group = "The factory"
sync = "even"
why = "Submodule of this repo: the kickstart realm."
why = "The kickstart realm of that factory."
[[fork]]
name = "cloudroom"
upstream = "davidondrej/cloudroom"
group = "Agents and memory"
sync = "2 behind"
why = "A platform to run many agents; this repo vendors its `adr-verbatim` skill."
[[fork]]
name = "skills"
@@ -91,13 +105,6 @@ group = "Agents and memory"
sync = "even"
why = "Skills that orchestrate coding agents on long tasks."
[[fork]]
name = "rea"
upstream = "morluto/rea"
group = "Agents and memory"
sync = "761 behind"
why = "Reverse engineering with agents."
[[fork]]
name = "TencentDB-Agent-Memory"
upstream = "TencentCloud/TencentDB-Agent-Memory"
@@ -154,13 +161,6 @@ group = "Runtimes and compilers"
sync = "even"
why = "A compiler-based safety checker for GPU kernels, in Lean 4."
[[fork]]
name = "thc"
upstream = "ekmett/thc"
group = "Runtimes and compilers"
sync = "even"
why = "The Turbo Haskell Compiler."
[[fork]]
name = "core"
upstream = "home-assistant/core"
@@ -168,30 +168,3 @@ group = "Other"
sync = "795 behind"
why = "Home Assistant: local home automation."
[[fork]]
name = "edit"
upstream = "fmhy/edit"
group = "Other"
sync = "7 behind"
why = "Changes to FMHY."
[[fork]]
name = "prj-gd-engine"
upstream = "mbracali/prj-gd-engine"
group = "Other"
sync = "179 behind"
why = "Re-implementations of guitar music games."
[[fork]]
name = "naruto-unison"
upstream = "naruto-unison/naruto-unison"
group = "Other"
sync = "even"
why = "Naruto Unison, a game."
[[fork]]
name = "OpenVoice"
upstream = "myshell-ai/OpenVoice"
group = "Other"
sync = "even"
why = "Instant voice cloning."
+6 -4
View File
@@ -2,18 +2,20 @@
# PIABROTA
Every public repo of [piabrota](https://github.com/piabrota), an open software fabric made in Rio de
Janeiro: {{ umbrella|length + project|length + fork|length }} public repos, as of {{ meta.as_of }}. The rules
are in [DOGMA.md](DOGMA.md). The org's {{ meta.private_count }} private repos are counted, never listed.
Janeiro: {{ chart|length + project|length + fork|length }} public repos, as of {{ meta.as_of }}. The rules
are in [DOGMA.md](DOGMA.md).{% if meta.private_count %} The org's {{ meta.private_count }} private repos are counted, never listed.{% endif %}
## Umbrella
## Company
| Repo | Licence | What it is |
| --- | --- | --- |
{% for r in umbrella -%}
{% for r in chart -%}
| [`{{ r.name }}`](https://github.com/piabrota/{{ r.name }}) | {{ r.licence }} | {{ r.what }} |
{% endfor %}
## Projects
The projects are the submodules under [`products/`](products/).
| Repo | Lane | Licence | What it is | Its place in the company |
| --- | --- | --- | --- | --- |
{% for r in project -%}