tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1569Shell 203Rust 109Markdown 993728 Sutichaykuna

Scaffold inicial: workspace Rust + SDDs completos

Arranque del proyecto hammer (distro AI-nativa: laboratorio funcional en el
sótano, terminal mutable clásica arriba, integración de IA programadora).

- Workspace Rust (compila, tests verdes): hammer-core, hammer-build,
  hammer-cli (bin `hammer`), hammerd.
- SDDs 00-10 + 6 ADRs en docs/ con toda la arquitectura.
- Esqueletos navegables mapeados a las fases del roadmap; Fase 0/1 listas
  para implementar el sandbox real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

8bf1623044075274682e4351a0f8e120047c2bed · ruwaq sergio · (4 killa ñawpaq) · kay commitpi sach'ata qhaway

Semántico sayk'uy · 55

crates/hammer-build/src/lib.rs

crates/hammer-build/src/sandbox.rs

crates/hammer-cli/src/main.rs

crates/hammer-core/src/hash.rs

crates/hammer-core/src/lib.rs

crates/hammer-core/src/recipe.rs

crates/hammer-core/src/store.rs

crates/hammer-core/src/swm.rs

crates/hammerd/src/main.rs

37 qillqakuna · +2746 −0

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..68d4f536
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+# Rust
+/target
+**/*.rs.bk
+Cargo.lock.orig
+
+# hammer local state (never commit the store or runtime state)
+/store/
+/var/
+*.swm.local
+
+# editor / OS
+.DS_Store
+*.swp
+.idea/
+.vscode/
+Conversación co.txt
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 00000000..cab0b2bc
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,592 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "blake3"
+version = "1.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "cpufeatures",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "clap"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "hammer-build"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "hammer-core",
+ "thiserror",
+ "tracing",
+]
+
+[[package]]
+name = "hammer-cli"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "clap",
+ "hammer-build",
+ "hammer-core",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "hammer-core"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "blake3",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "thiserror",
+]
+
+[[package]]
+name = "hammerd"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "clap",
+ "hammer-core",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "log"
+version = "0.4.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
+
+[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..3df1b7a3
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,38 @@
+[workspace]
+resolver = "2"
+members = [
+    "crates/hammer-core",
+    "crates/hammer-build",
+    "crates/hammer-cli",
+    "crates/hammerd",
+]
+
+[workspace.package]
+version = "0.0.1"
+edition = "2021"
+license = "MIT"
+authors = ["sergio <gerencia@jlsoltech.com>"]
+repository = "https://gitea.gioser.net/sergio/hammer"
+
+[workspace.dependencies]
+hammer-core = { path = "crates/hammer-core" }
+hammer-build = { path = "crates/hammer-build" }
+
+# shared third-party deps, pinned at the workspace level
+anyhow = "1"
+thiserror = "2"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+serde_yaml = "0.9"
+blake3 = "1"
+clap = { version = "4", features = ["derive"] }
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+
+[profile.release]
+# small, static-friendly binaries for the userland
+opt-level = "z"
+lto = true
+codegen-units = 1
+strip = true
+panic = "abort"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..caaf261c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 sergio
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..42f49ea8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,67 @@
+# hammer
+
+> Una distribución Linux construida con un **laboratorio funcional y hermético** en el
+> sótano, y una **terminal mutable, clásica y anárquica** en el piso de arriba — diseñada
+> desde el suelo para que una **IA programadora** entienda, modifique y comparta el sistema.
+
+`hammer` no es otro gestor de paquetes inmutable. Es una arquitectura de dos mundos:
+
+- **El laboratorio** compila desde fuentes upstream (commits fijados), de forma
+  determinista y aislada (`bubblewrap` + `zig cc` + musl estático), y direcciona cada
+  artefacto por su hash (BLAKE3) en un *content-addressed store*.
+- **El userland** es un Linux clásico, mutable, con FHS de verdad (`/bin`, `/lib`, `/etc`).
+  Los binarios se **hidratan** desde el store por *hardlinks*. Puedes pisar archivos en
+  caliente, romper cosas con un `rm -rf`, y revertir cuando quieras.
+
+Entre ambos mundos viven las tres piezas que hacen a `hammer` distinto:
+
+1. **Overlay de experimentación** — prueba cambios sobre el sistema real con red de
+   seguridad; `hammer try` / `commit` / `discard`.
+2. **Diario de mutaciones** — un daemon `fanotify` registra todo lo que tú (o la IA)
+   cambiáis a mano. Vives imperativamente; el sistema genera el delta contra la base
+   limpia. **El diario es tu configuración — sin ser declarativa.**
+3. **Manifiesto `.swm`** — compartes la *receta de la mutación* (parche de fuente + flags +
+   ediciones de config), no el binario cocinado. El receptor **reproduce y verifica**; no
+   confía en tu binario.
+
+Encima de todo corre el **bus de agente** (`/run/agent.sock`): la IA habla un protocolo
+pequeño y legible, dispara compilaciones, inyecta en el overlay, escucha fallos y reacciona.
+Tú tienes la última palabra.
+
+## Estado
+
+Fase de arranque. Validamos la capa AI-nativa **sobre Alpine** (musl + FHS ya cocidos)
+antes de bajar a distro propia. Ver [`docs/10-roadmap.md`](docs/10-roadmap.md).
+
+## Documentación de diseño (SDD)
+
+Toda la arquitectura está en [`docs/`](docs/). Empieza por
+[`docs/00-vision.md`](docs/00-vision.md) y [`docs/01-architecture.md`](docs/01-architecture.md).
+
+## Estructura
+
+```
+crates/
+  hammer-core   tipos compartidos: Recipe, Swm, hashing CAS, store
+  hammer-build  el laboratorio: sandbox + compilación + hidratación
+  hammer-cli    el binario `hammer` (build, hydrate, try, commit, apply, export…)
+  hammerd       daemon: bus de agente + diario de mutaciones
+docs/           SDDs y ADRs
+```
+
+## Stack
+
+| Capa | Decisión |
+|---|---|
+| Base de validación | Alpine (musl + FHS mutable) |
+| Tooling / daemons | Rust (estático-musl) |
+| Compilador del lab | `zig cc` por defecto, pluggable por receta |
+| Sandbox de build | bubblewrap (namespaces) |
+| Direccionamiento | BLAKE3 content-addressed store |
+| Despliegue | Hidratación por hardlinks + patchelf |
+
+## Filosofía
+
+> La automatización es mi empleada en el sótano, pero en el piso de arriba mando yo.
+
+Eficiencia matemática en la manufactura, libertad biológica en la ejecución.
diff --git a/crates/hammer-build/Cargo.toml b/crates/hammer-build/Cargo.toml
new file mode 100644
index 00000000..7e87058e
--- /dev/null
+++ b/crates/hammer-build/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "hammer-build"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "El laboratorio de hammer: sandbox de build (bubblewrap + zig cc) e hidratación."
+
+[dependencies]
+hammer-core.workspace = true
+anyhow.workspace = true
+thiserror.workspace = true
+tracing.workspace = true
diff --git a/crates/hammer-build/src/lib.rs b/crates/hammer-build/src/lib.rs
new file mode 100644
index 00000000..db836ecb
--- /dev/null
+++ b/crates/hammer-build/src/lib.rs
@@ -0,0 +1,55 @@
+//! El laboratorio: compila una receta de forma hermética y la sella en el store; e hidrata
+//! artefactos al FHS. Ver `docs/02-build-lab.md` y `docs/03-hydration.md`.
+//!
+//! Esqueleto de Fase 0. Las funciones públicas fijan el contrato; la implementación del
+//! sandbox (bubblewrap) y de patchelf se irá rellenando.
+
+use std::path::Path;
+
+use hammer_core::{ArtifactHash, LinkMode, Recipe, Store};
+
+pub mod sandbox;
+
+/// Calcula el `ArtifactHash` de una receta, resolviendo recursivamente sus deps de build.
+/// Ver `docs/02-build-lab.md` §2 y §5.
+pub fn artifact_hash(recipe: &Recipe, store: &Store) -> hammer_core::Result<ArtifactHash> {
+    let dep_hashes: Vec<ArtifactHash> = Vec::new();
+    for dep_name in &recipe.deps.build {
+        // TODO(fase-0): cargar la receta de la dep y recursar. Por ahora se documenta el
+        // contrato; el grafo real se implementa con `hammer build`.
+        let _ = dep_name;
+    }
+    let inputs = recipe.hash_inputs(&dep_hashes);
+    let refs: Vec<&[u8]> = inputs.iter().map(|v| v.as_slice()).collect();
+    let _ = store;
+    Ok(ArtifactHash::of_inputs(&refs))
+}
+
+/// Compila una receta y devuelve el hash del artefacto sellado en el store.
+/// Si el hash ya existe en el store, devuelve sin recompilar (caché).
+pub fn build(recipe: &Recipe, store: &Store) -> hammer_core::Result<ArtifactHash> {
+    let h = artifact_hash(recipe, store)?;
+    if store.has(&h, &recipe.name) {
+        tracing::info!(hash = %h, name = %recipe.name, "caché: artefacto ya en el store");
+        return Ok(h);
+    }
+    // TODO(fase-0): resolver deps → make_sandbox → run_phases(patch/configure/compile/install)
+    //               → store.seal(out, &h, &recipe.name).
+    tracing::warn!("build real pendiente (Fase 0): sandbox bubblewrap + zig cc");
+    Err(hammer_core::Error::Other(anyhow::anyhow!(
+        "build no implementado todavía; ver docs/10-roadmap.md (Fase 0)"
+    )))
+}
+
+/// Proyecta un artefacto del store al FHS (real o de overlay). Ver `docs/03-hydration.md`.
+pub fn hydrate(
+    _h: &ArtifactHash,
+    _store: &Store,
+    _target_fhs: &Path,
+    _mode: LinkMode,
+) -> hammer_core::Result<()> {
+    // TODO(fase-1): hardlink del store al FHS; patchelf (set-interpreter/set-rpath) si Dynamic.
+    Err(hammer_core::Error::Other(anyhow::anyhow!(
+        "hidratación no implementada todavía; ver docs/10-roadmap.md (Fase 1)"
+    )))
+}
diff --git a/crates/hammer-build/src/sandbox.rs b/crates/hammer-build/src/sandbox.rs
new file mode 100644
index 00000000..f62cceae
--- /dev/null
+++ b/crates/hammer-build/src/sandbox.rs
@@ -0,0 +1,41 @@
+//! El sandbox hermético de build (bubblewrap). Ver `docs/02-build-lab.md` §3 y §4.
+//!
+//! Esqueleto de Fase 0. Define la forma del aislamiento que implementaremos: raíz tmpfs,
+//! compilador read-only inyectado, fuentes/deps read-only, sin red, salida vía DESTDIR.
+
+use std::path::PathBuf;
+
+/// Descripción de un sandbox de build a montar con `bwrap`.
+#[derive(Debug, Clone, Default)]
+pub struct Sandbox {
+    /// Binds read-only: (origen_host, destino_sandbox).
+    pub ro_binds: Vec<(PathBuf, PathBuf)>,
+    /// Directorio de salida (DESTDIR) dentro del sandbox.
+    pub out: PathBuf,
+    /// Aislar red (hermeticidad: el build no descarga nada no declarado).
+    pub isolate_net: bool,
+}
+
+impl Sandbox {
+    /// Construye los argumentos para `bwrap`. TODO(fase-0): completar y ejecutar.
+    pub fn bwrap_args(&self) -> Vec<String> {
+        let mut args = vec![
+            "--unshare-all".into(),
+            "--tmpfs".into(),
+            "/".into(),
+            "--proc".into(),
+            "/proc".into(),
+            "--dev".into(),
+            "/dev".into(),
+        ];
+        if !self.isolate_net {
+            args.push("--share-net".into());
+        }
+        for (src, dst) in &self.ro_binds {
+            args.push("--ro-bind".into());
+            args.push(src.display().to_string());
+            args.push(dst.display().to_string());
+        }
+        args
+    }
+}
diff --git a/crates/hammer-cli/Cargo.toml b/crates/hammer-cli/Cargo.toml
new file mode 100644
index 00000000..ec6e3fb9
--- /dev/null
+++ b/crates/hammer-cli/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "hammer-cli"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "El binario `hammer`: orquesta build, hydrate, try/commit, apply/export y ctl."
+
+[[bin]]
+name = "hammer"
+path = "src/main.rs"
+
+[dependencies]
+hammer-core.workspace = true
+hammer-build.workspace = true
+anyhow.workspace = true
+clap.workspace = true
+tracing.workspace = true
+tracing-subscriber.workspace = true
diff --git a/crates/hammer-cli/src/main.rs b/crates/hammer-cli/src/main.rs
new file mode 100644
index 00000000..72466f84
--- /dev/null
+++ b/crates/hammer-cli/src/main.rs
@@ -0,0 +1,99 @@
+//! `hammer` — el punto de entrada de todo flujo manual. Ver `docs/`.
+//!
+//! Los subcomandos están mapeados a las fases del roadmap (`docs/10-roadmap.md`). Los que aún
+//! no están implementados devuelven un error claro indicando su fase, para que el esqueleto
+//! sea navegable desde el día uno.
+
+use clap::{Parser, Subcommand};
+
+const DEFAULT_STORE: &str = "/store";
+
+#[derive(Parser)]
+#[command(
+    name = "hammer",
+    version,
+    about = "Laboratorio funcional en el sótano, terminal mutable arriba.",
+    long_about = "hammer: distro AI-nativa. Ver docs/ para el diseño completo."
+)]
+struct Cli {
+    /// Ruta del content-addressed store.
+    #[arg(long, default_value = DEFAULT_STORE, global = true)]
+    store: String,
+
+    #[command(subcommand)]
+    cmd: Cmd,
+}
+
+#[derive(Subcommand)]
+enum Cmd {
+    /// [Fase 0] Compila una receta y la sella en el store.
+    Build {
+        /// Ruta a la receta TOML.
+        recipe: String,
+    },
+    /// [Fase 1] Proyecta un artefacto del store al FHS (real o de overlay).
+    Hydrate {
+        hash: String,
+        #[arg(long, default_value = "/")]
+        into: String,
+    },
+    /// [Fase 2] Monta un overlay de experimentación sobre los directorios del sistema.
+    Try,
+    /// [Fase 2] Fusiona el overlay activo al FHS real (registra en el diario).
+    Commit,
+    /// [Fase 2] Descarta el overlay activo; vuelve al estado base.
+    Discard,
+    /// [Fase 2] Muestra el estado de overlays activos.
+    Status,
+    /// [Fase 3] Ver/seguir el diario de mutaciones.
+    Journal,
+    /// [Fase 4] Aplica un manifiesto .swm (reproduce y lo deja en un overlay).
+    Apply { file: String },
+    /// [Fase 4] Exporta el delta del sistema como manifiesto .swm.
+    Export {
+        #[arg(long)]
+        base: Option<String>,
+    },
+    /// [Fase 5] Envía un comando al init (proxy a /run/init.control).
+    Ctl { line: String },
+}
+
+fn main() -> anyhow::Result<()> {
+    tracing_subscriber::fmt()
+        .with_env_filter(
+            tracing_subscriber::EnvFilter::try_from_default_env()
+                .unwrap_or_else(|_| "info".into()),
+        )
+        .init();
+
+    let cli = Cli::parse();
+    let store = hammer_core::Store::open(&cli.store)?;
+
+    match cli.cmd {
+        Cmd::Build { recipe } => {
+            let text = std::fs::read_to_string(&recipe)?;
+            let recipe = hammer_core::Recipe::from_toml(&text)?;
+            let hash = hammer_build::build(&recipe, &store)?;
+            println!("{hash}");
+        }
+        Cmd::Hydrate { hash, into } => {
+            println!("[fase 1 pendiente] hydrate {hash} into {into}");
+        }
+        Cmd::Try | Cmd::Commit | Cmd::Discard | Cmd::Status => {
+            println!("[fase 2 pendiente] overlay — ver docs/04-overlay.md");
+        }
+        Cmd::Journal => {
+            println!("[fase 3 pendiente] diario — ver docs/05-journal.md");
+        }
+        Cmd::Apply { file } => {
+            println!("[fase 4 pendiente] apply {file} — ver docs/06-swm-format.md");
+        }
+        Cmd::Export { base } => {
+            println!("[fase 4 pendiente] export base={base:?} — ver docs/05-journal.md");
+        }
+        Cmd::Ctl { line } => {
+            println!("[fase 5 pendiente] ctl {line:?} — ver docs/07-agent-bus.md");
+        }
+    }
+    Ok(())
+}
diff --git a/crates/hammer-core/Cargo.toml b/crates/hammer-core/Cargo.toml
new file mode 100644
index 00000000..e86602a1
--- /dev/null
+++ b/crates/hammer-core/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "hammer-core"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "Tipos compartidos de hammer: Recipe, Swm, hashing CAS y el store."
+
+[dependencies]
+anyhow.workspace = true
+thiserror.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+serde_yaml.workspace = true
+blake3.workspace = true
diff --git a/crates/hammer-core/src/hash.rs b/crates/hammer-core/src/hash.rs
new file mode 100644
index 00000000..f912751d
--- /dev/null
+++ b/crates/hammer-core/src/hash.rs
@@ -0,0 +1,66 @@
+//! Direccionamiento por contenido (CAS). Ver `docs/02-build-lab.md` §2.
+//!
+//! El `ArtifactHash` identifica un artefacto por TODO lo que influye en su salida:
+//! commit fuente + parches + flags/compilador/target + hashes de dependencias.
+
+use serde::{Deserialize, Serialize};
+
+/// Hash BLAKE3 de un artefacto, con prefijo legible `b3:`.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct ArtifactHash(String);
+
+impl ArtifactHash {
+    /// Construye desde bytes ya hasheados (representación hex).
+    pub fn from_hex(hex: impl Into<String>) -> Self {
+        ArtifactHash(format!("b3:{}", hex.into()))
+    }
+
+    /// Hashea un conjunto ordenado de entradas. El llamador es responsable de pasar las
+    /// entradas en orden canónico y estable (ver `docs/02-build-lab.md` §2).
+    pub fn of_inputs(inputs: &[&[u8]]) -> Self {
+        let mut hasher = blake3::Hasher::new();
+        for chunk in inputs {
+            // length-prefijado para evitar colisiones por concatenación ambigua.
+            hasher.update(&(chunk.len() as u64).to_le_bytes());
+            hasher.update(chunk);
+        }
+        ArtifactHash(format!("b3:{}", hasher.finalize().to_hex()))
+    }
+
+    /// Forma corta para directorios del store: `<hash-sin-prefijo>-<name>`.
+    pub fn store_dir_name(&self, name: &str) -> String {
+        let bare = self.0.strip_prefix("b3:").unwrap_or(&self.0);
+        format!("{bare}-{name}")
+    }
+
+    pub fn as_str(&self) -> &str {
+        &self.0
+    }
+}
+
+impl std::fmt::Display for ArtifactHash {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(&self.0)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn deterministic_and_order_sensitive() {
+        let a = ArtifactHash::of_inputs(&[b"grep", b"abc123", b"--static"]);
+        let b = ArtifactHash::of_inputs(&[b"grep", b"abc123", b"--static"]);
+        assert_eq!(a, b, "misma entrada ⇒ mismo hash");
+
+        let c = ArtifactHash::of_inputs(&[b"abc123", b"grep", b"--static"]);
+        assert_ne!(a, c, "orden distinto ⇒ hash distinto");
+    }
+
+    #[test]
+    fn store_dir_name_strips_prefix() {
+        let h = ArtifactHash::from_hex("deadbeef");
+        assert_eq!(h.store_dir_name("grep"), "deadbeef-grep");
+    }
+}
diff --git a/crates/hammer-core/src/lib.rs b/crates/hammer-core/src/lib.rs
new file mode 100644
index 00000000..1454cfa1
--- /dev/null
+++ b/crates/hammer-core/src/lib.rs
@@ -0,0 +1,32 @@
+//! Tipos núcleo de hammer, compartidos por el lab, la CLI y el daemon.
+//!
+//! Ver `docs/01-architecture.md` y siguientes. Esto es el esqueleto de Fase 0: los tipos y
+//! contratos están definidos; la lógica pesada (sandbox, fanotify, bus) vive en los otros
+//! crates y se irá rellenando por fase.
+
+pub mod hash;
+pub mod recipe;
+pub mod store;
+pub mod swm;
+
+pub use hash::ArtifactHash;
+pub use recipe::{Compiler, LinkMode, Recipe};
+pub use store::Store;
+pub use swm::Swm;
+
+/// Error común del ecosistema hammer.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    #[error("io: {0}")]
+    Io(#[from] std::io::Error),
+    #[error("serialización: {0}")]
+    Serde(String),
+    #[error("receta inválida: {0}")]
+    Recipe(String),
+    #[error("store: {0}")]
+    Store(String),
+    #[error(transparent)]
+    Other(#[from] anyhow::Error),
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/crates/hammer-core/src/recipe.rs b/crates/hammer-core/src/recipe.rs
new file mode 100644
index 00000000..53ede4d2
--- /dev/null
+++ b/crates/hammer-core/src/recipe.rs
@@ -0,0 +1,109 @@
+//! La `Recipe`: descripción pura de un build. Ver `docs/02-build-lab.md` §1.
+
+use serde::{Deserialize, Serialize};
+
+use crate::hash::ArtifactHash;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Recipe {
+    pub name: String,
+    pub version: String,
+    pub source: Source,
+    pub build: Build,
+    #[serde(default)]
+    pub deps: Deps,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Source {
+    pub repo: String,
+    /// Commit FIJADO. Nunca "HEAD". Ver ADR 0006.
+    pub commit: String,
+    #[serde(default)]
+    pub patches: Vec<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Build {
+    #[serde(default)]
+    pub compiler: Compiler,
+    #[serde(default = "default_target")]
+    pub target: String,
+    #[serde(default)]
+    pub link: LinkMode,
+    #[serde(default)]
+    pub flags: Vec<String>,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
+pub struct Deps {
+    #[serde(default)]
+    pub build: Vec<String>,
+    #[serde(default)]
+    pub runtime: Vec<String>,
+}
+
+/// Compilador del lab, POR RECETA (no global). `zig-cc` por defecto; escotilla a clang/gcc
+/// para paquetes con gcc-ismos. Ver ADR 0003.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum Compiler {
+    #[default]
+    ZigCc,
+    Clang,
+    Gcc,
+}
+
+impl Compiler {
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            Compiler::ZigCc => "zig-cc",
+            Compiler::Clang => "clang",
+            Compiler::Gcc => "gcc",
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum LinkMode {
+    #[default]
+    Static,
+    Dynamic,
+}
+
+fn default_target() -> String {
+    "x86_64-linux-musl".to_string()
+}
+
+impl Recipe {
+    pub fn from_toml(_s: &str) -> crate::Result<Recipe> {
+        // TODO(fase-0): parsear TOML. Por ahora el parsing real lo añadiremos al implementar
+        // `hammer build`; el contrato (esta struct) ya está fijado.
+        Err(crate::Error::Recipe(
+            "parsing de receta TOML pendiente (Fase 0)".into(),
+        ))
+    }
+
+    /// Las entradas canónicas que alimentan el `ArtifactHash` de esta receta.
+    /// NOTA: el hash final también incorpora los hashes de las deps de build (recursivo),
+    /// que el lab resuelve antes de llamar aquí. Ver `docs/02-build-lab.md` §2 y §5.
+    pub fn hash_inputs(&self, dep_hashes: &[ArtifactHash]) -> Vec<Vec<u8>> {
+        let mut v: Vec<Vec<u8>> = vec![
+            self.source.commit.as_bytes().to_vec(),
+            self.build.compiler.as_str().as_bytes().to_vec(),
+            self.build.target.as_bytes().to_vec(),
+            format!("{:?}", self.build.link).into_bytes(),
+        ];
+        for p in &self.source.patches {
+            v.push(p.as_bytes().to_vec());
+        }
+        for f in &self.build.flags {
+            v.push(f.as_bytes().to_vec());
+        }
+        for d in dep_hashes {
+            v.push(d.as_str().as_bytes().to_vec());
+        }
+        v
+    }
+}
diff --git a/crates/hammer-core/src/store.rs b/crates/hammer-core/src/store.rs
new file mode 100644
index 00000000..d953bd26
--- /dev/null
+++ b/crates/hammer-core/src/store.rs
@@ -0,0 +1,49 @@
+//! El content-addressed store. Ver `docs/03-hydration.md` §1.
+//!
+//! Inmutable, append-only, direccionado por `ArtifactHash`. Esqueleto de Fase 0: la API está
+//! fijada; el sellado real (mover el árbol de salida del sandbox e idealmente hacerlo de sólo
+//! lectura) se completa al implementar el builder.
+
+use std::path::{Path, PathBuf};
+
+use crate::hash::ArtifactHash;
+
+pub struct Store {
+    root: PathBuf,
+}
+
+impl Store {
+    /// Abre (o prepara) un store en `root` (p. ej. `/store`).
+    pub fn open(root: impl Into<PathBuf>) -> crate::Result<Self> {
+        let root = root.into();
+        std::fs::create_dir_all(&root)?;
+        Ok(Store { root })
+    }
+
+    pub fn root(&self) -> &Path {
+        &self.root
+    }
+
+    /// Ruta del artefacto en el store para un hash + nombre legible.
+    pub fn path_of(&self, h: &ArtifactHash, name: &str) -> PathBuf {
+        self.root.join(h.store_dir_name(name))
+    }
+
+    /// ¿Ya existe el artefacto? (caché del lab; ver `docs/02-build-lab.md` §5).
+    pub fn has(&self, h: &ArtifactHash, name: &str) -> bool {
+        self.path_of(h, name).is_dir()
+    }
+
+    /// Sella el árbol de salida de un build en el store bajo su hash.
+    /// TODO(fase-0): mover `out_dir` a la ruta del store y marcarlo read-only.
+    pub fn seal(
+        &self,
+        _out_dir: &Path,
+        _h: &ArtifactHash,
+        _name: &str,
+    ) -> crate::Result<PathBuf> {
+        Err(crate::Error::Store(
+            "sellado en el store pendiente (Fase 0)".into(),
+        ))
+    }
+}
diff --git a/crates/hammer-core/src/swm.rs b/crates/hammer-core/src/swm.rs
new file mode 100644
index 00000000..bd6abb68
--- /dev/null
+++ b/crates/hammer-core/src/swm.rs
@@ -0,0 +1,121 @@
+//! El manifiesto `.swm` (Software Mutación). Ver `docs/06-swm-format.md`.
+//!
+//! Es la unidad de intercambio: receta de transformación sobre fuente pública + ediciones de
+//! config. NUNCA transporta binarios cocidos (salvo `FileDrop` con hash declarado).
+
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Swm {
+    pub swm_version: u32,
+    pub base: Base,
+    pub mutations: Vec<Mutation>,
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub signature: Option<Signature>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Base {
+    pub distro_version: String,
+    #[serde(default)]
+    pub pins: std::collections::BTreeMap<String, String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(tag = "type", rename_all = "snake_case")]
+pub enum Mutation {
+    SourcePatch {
+        repo: String,
+        commit: String,
+        #[serde(default, skip_serializing_if = "Option::is_none")]
+        patch: Option<String>,
+        #[serde(default, skip_serializing_if = "Option::is_none")]
+        patch_url: Option<String>,
+        build: SwmBuild,
+        target_bin: String,
+        #[serde(default, skip_serializing_if = "Option::is_none")]
+        expected_hash: Option<String>,
+    },
+    ConfigEdit {
+        file: String,
+        inline_diff: String,
+    },
+    InitRule {
+        action: String,
+        service: String,
+        command: String,
+    },
+    FileDrop {
+        path: String,
+        /// hash BLAKE3 del contenido, declarado para verificación.
+        content_hash: String,
+        #[serde(default, skip_serializing_if = "Option::is_none")]
+        content_url: Option<String>,
+    },
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SwmBuild {
+    #[serde(default = "default_compiler")]
+    pub compiler: String,
+    #[serde(default = "default_target")]
+    pub target: String,
+    #[serde(default = "default_link")]
+    pub link: String,
+    #[serde(default)]
+    pub flags: Vec<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Signature {
+    pub by: String,
+    pub alg: String,
+    pub sig: String,
+}
+
+fn default_compiler() -> String {
+    "zig-cc".into()
+}
+fn default_target() -> String {
+    "x86_64-linux-musl".into()
+}
+fn default_link() -> String {
+    "static".into()
+}
+
+impl Swm {
+    pub fn from_yaml(s: &str) -> crate::Result<Swm> {
+        serde_yaml::from_str(s).map_err(|e| crate::Error::Serde(e.to_string()))
+    }
+
+    pub fn to_yaml(&self) -> crate::Result<String> {
+        serde_yaml::to_string(self).map_err(|e| crate::Error::Serde(e.to_string()))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn roundtrip_yaml() {
+        let yaml = r#"
+swm_version: 1
+base:
+  distro_version: "2026-06-06"
+  pins:
+    grep: "a1b2c3d"
+mutations:
+  - type: config_edit
+    file: "/etc/network.conf"
+    inline_diff: |
+      - DHCP=yes
+      + IP=192.168.1.100
+"#;
+        let swm = Swm::from_yaml(yaml).expect("parse");
+        assert_eq!(swm.swm_version, 1);
+        assert_eq!(swm.mutations.len(), 1);
+        let back = swm.to_yaml().expect("serialize");
+        assert!(back.contains("config_edit"));
+    }
+}
diff --git a/crates/hammerd/Cargo.toml b/crates/hammerd/Cargo.toml
new file mode 100644
index 00000000..eb8a5e22
--- /dev/null
+++ b/crates/hammerd/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "hammerd"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+authors.workspace = true
+repository.workspace = true
+description = "Daemon de hammer: bus de agente (/run/agent.sock) y diario de mutaciones (fanotify)."
+
+[[bin]]
+name = "hammerd"
+path = "src/main.rs"
+
+[dependencies]
+hammer-core.workspace = true
+anyhow.workspace = true
+clap.workspace = true
+tracing.workspace = true
+tracing-subscriber.workspace = true
diff --git a/crates/hammerd/src/main.rs b/crates/hammerd/src/main.rs
new file mode 100644
index 00000000..83960269
--- /dev/null
+++ b/crates/hammerd/src/main.rs
@@ -0,0 +1,44 @@
+//! `hammerd` — daemon de hammer. Dos responsabilidades:
+//!   1. Bus de agente: /run/agent.sock (JSON-líneas, SO_PEERCRED). Ver `docs/07-agent-bus.md`.
+//!   2. Diario de mutaciones: fanotify sobre /bin,/sbin,/lib,/etc. Ver `docs/05-journal.md`.
+//!
+//! Esqueleto de arranque. Las dos subsistemas (Fases 3 y 5) se implementarán por separado;
+//! aquí queda el binario navegable y el cableado básico de logging/argumentos.
+
+use clap::Parser;
+
+#[derive(Parser)]
+#[command(name = "hammerd", version, about = "Daemon de hammer: bus de agente + diario.")]
+struct Args {
+    /// Socket del bus de agente.
+    #[arg(long, default_value = "/run/agent.sock")]
+    agent_sock: String,
+    /// FIFO de control humano del init.
+    #[arg(long, default_value = "/run/init.control")]
+    init_control: String,
+    /// Directorio del diario de mutaciones.
+    #[arg(long, default_value = "/var/lib/hammer/journal")]
+    journal: String,
+}
+
+fn main() -> anyhow::Result<()> {
+    tracing_subscriber::fmt()
+        .with_env_filter(
+            tracing_subscriber::EnvFilter::try_from_default_env()
+                .unwrap_or_else(|_| "info".into()),
+        )
+        .init();
+
+    let args = Args::parse();
+    tracing::info!(
+        agent_sock = %args.agent_sock,
+        init_control = %args.init_control,
+        journal = %args.journal,
+        "hammerd: arranque (esqueleto)"
+    );
+
+    // TODO(fase-3): iniciar el watcher fanotify → diario.
+    // TODO(fase-5): servir el bus de agente en agent_sock (JSON-líneas, SO_PEERCRED).
+    tracing::warn!("subsistemas pendientes: diario (Fase 3) y bus de agente (Fase 5)");
+    Ok(())
+}
diff --git a/docs/00-vision.md b/docs/00-vision.md
new file mode 100644
index 00000000..b3ce0d0b
--- /dev/null
+++ b/docs/00-vision.md
@@ -0,0 +1,77 @@
+# SDD 00 — Visión y filosofía
+
+## 1. El problema
+
+El panorama de distribuciones Linux te obliga a elegir entre dos extremos malos:
+
+- **Inmutables / declarativas** (NixOS, Guix, Fedora Silverblue): determinismo y
+  reproducibilidad reales, pero a costa de tu agencia. El sistema operativo *es* el grafo.
+  Pierdes la estructura familiar de directorios, pierdes el control directo en la terminal,
+  y vives editando un archivo de configuración abstracto en lugar de habitar el sistema.
+  Para una herramienta de automatización (una IA), además, la complejidad está *oculta tras
+  capas de abstracción* que la obligan a simular a un humano.
+
+- **Tradicionales / imperativas** (Arch, Gentoo, Slackware): control y mutabilidad totales,
+  pero con el tiempo se pudren — el gestor de paquetes pierde el rastro de lo que el usuario
+  hizo a mano, se acumulan archivos huérfanos, y reproducir tu sistema en otra máquina es
+  imposible sin documentar cada acción manualmente.
+
+Ninguno de los dos sirve bien para el escenario que viene: **un usuario con una IA
+programadora que entiende, modifica y comparte su sistema en cualquier contexto.**
+
+## 2. La tesis
+
+Se puede tener lo mejor de ambos separando dos mundos que hoy están fusionados:
+
+> **La automatización funcional es mi empleada en el sótano. En el piso de arriba mando yo.**
+
+- **El sótano (el laboratorio):** compilación determinista, hermética, direccionada por
+  contenido. Aquí reina la teoría de grafos y el hashing. Cero efectos secundarios.
+- **El piso de arriba (el userland):** un Linux clásico, mutable, con `/bin`, `/lib`, `/etc`
+  reales. Aquí reina el usuario. Un `rm -rf` rompe cosas de verdad. La terminal es un espacio
+  vivo de interacción directa, no la interfaz de lectura de un archivo de config.
+
+El puente entre ambos es la **hidratación**: los artefactos del store se proyectan al FHS
+real por hardlinks, normalizados para no arrastrar rutas del store.
+
+## 3. Por qué esto es AI-nativo (el verdadero diferenciador)
+
+La distro en sí no es la innovación — ensamblar componentes conocidos (musl, busybox, un
+kernel) es trabajo conocido. **La innovación es el substrato de baja entropía** que resulta:
+
+1. **Compilación determinista** → la IA pide cambios de fuente, recompila en el lab aislado,
+   y el binario es predecible. Vuelve atrás sin dramas.
+2. **El sistema ejecutable es texto plano + binarios atómicos** → la IA no parsea bases de
+   datos binarias de configuración (registro de Windows, journal de systemd). Lee/escribe
+   archivos e inspecciona binarios con `readelf`/`objdump`.
+3. **Mutabilidad = agencia real** → la IA experimenta en un overlay y promueve cambios. Si se
+   equivoca, desmontas la capa. Sin rollbacks complejos ni snapshots pesados.
+4. **musl mantiene el código C legible** para el contexto de un LLM (glibc es un laberinto de
+   macros prehistóricas).
+5. **El enlazado estático** garantiza que una herramienta mutada por la IA corre sin romper
+   enlaces de librerías en otros programas.
+
+Mientras la industria diseña sistemas para *proteger al sistema del administrador*
+(restringiendo, aislando, inmutabilizando) — y al hacerlo también ciega a las herramientas de
+IA — `hammer` hace lo contrario: **mantiene las tuberías expuestas y de baja entropía**, y
+trata al usuario (y a su IA) como un operador consciente, no como un peligro.
+
+## 4. Principios de diseño
+
+- **Determinismo en la fábrica, libertad en la ejecución.** No negociar ninguno de los dos.
+- **Texto plano y binarios atómicos por encima de bases de datos opacas.** Si algo del sistema
+  no se puede `cat`, `grep` o `readelf`, es una bandera roja.
+- **Verificar, no confiar.** Se comparten recetas reproducibles, nunca binarios cocidos.
+- **La IA propone; el humano dispone.** Toda acción de la IA es reversible y queda registrada.
+- **No reinventar lo resuelto.** Usamos motores y compiladores existentes como herramientas;
+  el valor está en el pegamento AI-nativo, no en reescribir Nix o un toolchain.
+- **El diario es la verdad.** Vives imperativamente; el sistema deriva el estado declarativo
+  *a posteriori*. Nunca al revés.
+
+## 5. Anti-objetivos (lo que `hammer` NO es)
+
+- No es un gestor de paquetes inmutable ni un daemon que restaura estado.
+- No reescribe un motor de build desde cero (ver [ADR 0004](adr/0004-no-custom-nix.md)).
+- No compila contra `HEAD` vivo a ciegas (ver [ADR 0006](adr/0006-pinned-commits.md)).
+- No oculta complejidad tras abstracciones que cieguen al usuario o a la IA.
+- No promete estabilidad de ABL de musl como magia (ver [SDD 03](03-hydration.md)).
diff --git a/docs/01-architecture.md b/docs/01-architecture.md
new file mode 100644
index 00000000..dea3c8c7
--- /dev/null
+++ b/docs/01-architecture.md
@@ -0,0 +1,99 @@
+# SDD 01 — Arquitectura general
+
+## 1. El modelo de dos mundos
+
+```
+                          EL SÓTANO (laboratorio)                 EL PISO DE ARRIBA (userland)
+                          determinista · hermético                mutable · clásico · FHS real
+   ┌──────────────────────────────────────────────┐   ┌─────────────────────────────────────────┐
+   │                                                │   │                                           │
+   │  [ Upstreams: git, commits FIJADOS ]           │   │   /bin  /sbin  /lib  /etc   (FHS clásico) │
+   │            │                                   │   │      ▲                                    │
+   │            ▼                                   │   │      │  hardlinks normalizados            │
+   │  ┌───────────────────────┐                     │   │      │                                    │
+   │  │  hammer-build (lab)    │                     │   │  ┌───┴──────────────┐                     │
+   │  │  bubblewrap + zig cc   │   compila musl      │   │  │   HIDRATACIÓN     │  patchelf / copy    │
+   │  │  recetas + grafo deps  │   estático          │   │  └───┬──────────────┘                     │
+   │  └──────────┬────────────┘                     │   │      │                                    │
+   │             ▼                                   │   │      │                                    │
+   │  ┌───────────────────────┐                     │   │  ┌───┴───────────────┐                    │
+   │  │  CAS store (BLAKE3)    │ ────────────────────┼───┼─▶│  overlay try/commit │ red de seguridad │
+   │  │  /store/<hash>-<name> │                     │   │  └───┬───────────────┘                    │
+   │  └───────────────────────┘                     │   │      │                                    │
+   │                                                │   │  ┌───┴───────────────┐                    │
+   └──────────────────────────────────────────────┘   │  │  diario fanotify    │  delta vs base    │
+                                                        │  └───┬───────────────┘                    │
+            ┌───────────────────────────────────────────────┐ │                                    │
+            │  BUS DE AGENTE  /run/agent.sock (JSON-líneas)   │◀┘   /run/init.control (FIFO humano)  │
+            │  COMPILE · INJECT · QUERY · eventos             │                                       │
+            └───────────────────────────┬────────────────────┘                                       │
+                                         │                    └─────────────────────────────────────┘
+                                         ▼
+                                  [ IA programadora ]  intención NL → .swm → overlay → test → aprobar
+```
+
+**Regla de oro:** los dos mundos nunca se mezclan. El lab jamás escribe directamente en el
+FHS real; siempre pasa por el store y luego por hidratación. El userland jamás compila contra
+el host; siempre delega al lab.
+
+## 2. Componentes y su responsabilidad
+
+| Componente | Crate | Responsabilidad única |
+|---|---|---|
+| **Laboratorio** | `hammer-build` | Compilar una receta de forma hermética → artefacto en el store |
+| **Store CAS** | `hammer-core` | Guardar/recuperar artefactos por hash BLAKE3; garbage collection |
+| **Hidratación** | `hammer-build` | Proyectar artefactos del store al FHS real (hardlink + patchelf) |
+| **Overlay** | `hammer-cli` | Montar/fusionar/descartar capa de experimentación en caliente |
+| **Diario** | `hammerd` | Vigilar mutaciones (fanotify), log append-only, exportar `.swm` |
+| **Bus de agente** | `hammerd` | Socket de control para IA/scripts; eventos del sistema |
+| **CLI** | `hammer-cli` | El binario `hammer` que orquesta todo lo anterior |
+| **Tipos compartidos** | `hammer-core` | `Recipe`, `Swm`, `Hash`, `Store`, formatos serializables |
+
+## 3. Flujo de datos canónico (de la intención al sistema vivo)
+
+1. **Intención** — el humano (o la IA) expresa un cambio: *"que grep ignore binarios por
+   defecto y use regex Perl"*.
+2. **Receta** — se traduce a una `Recipe`: repo + commit fijado + patch + flags + compilador.
+3. **Build** — `hammer-build` levanta el sandbox, compila con `zig cc`, produce un binario
+   musl estático, lo deposita en el store bajo `BLAKE3(...)`.
+4. **Overlay** — el artefacto se hidrata, pero **en una capa overlay temporal**, no en el
+   sistema real. El humano/IA prueba en caliente.
+5. **Validación** — corre el test harness; los eventos van por el bus (`BUILD_READY`,
+   `CRASHED`). Si falla, se descarta el overlay; el sistema base intacto.
+6. **Promoción** — si pasa, se fusiona al FHS real. El diario registra la mutación.
+7. **Compartir** — `hammer export` empaqueta el delta como `.swm`: base-hash + patch + config.
+   Otro usuario lo `apply`-ea: su IA reproduce y verifica localmente; nunca ejecuta tu binario.
+
+## 4. Estado en disco (layout)
+
+```
+/store/                      el content-addressed store (inmutable, append-only)
+  <blake3>-<name>/           un artefacto: árbol de archivos resultante de un build
+/var/lib/hammer/
+  recipes/                   recetas conocidas (caché de definiciones)
+  pins.toml                  lockfile: nombre → commit fijado del upstream
+  journal/                   diario de mutaciones append-only
+  overlays/                  upperdirs de overlays activos
+/run/
+  init.control              FIFO de control humano (texto crudo)
+  agent.sock                socket de control de agente (JSON-líneas, SO_PEERCRED)
+  hammerd.pid
+```
+
+> Nota: en la fase Alpine, `/store` y `/var/lib/hammer` viven dentro del rootfs de Alpine.
+> En la distro propia se decidirá su partición/montaje. Ver [SDD 10](10-roadmap.md).
+
+## 5. Límites del sistema (qué corre dónde)
+
+- **`hammer-build`** corre privilegiado lo justo para crear namespaces (vía `bubblewrap`,
+  que usa user-namespaces sin root real cuando es posible).
+- **`hammerd`** corre como servicio bajo el init; expone el bus y vigila el diario.
+- **`hammer` (CLI)** corre como el usuario; es el punto de entrada de todo flujo manual.
+- **La IA** es un cliente del bus como cualquier otro proceso — sin privilegios especiales
+  más allá de los que el humano le conceda explícitamente (ver [SDD 08](08-ai-integration.md)).
+
+## 6. Decisiones transversales
+
+- Reproducibilidad ⇒ commits fijados, no HEAD ([ADR 0006](adr/0006-pinned-commits.md)).
+- No reescribir el motor de build ([ADR 0004](adr/0004-no-custom-nix.md)).
+- Validar el concepto sobre Alpine primero ([ADR 0002](adr/0002-alpine-first.md)).
diff --git a/docs/02-build-lab.md b/docs/02-build-lab.md
new file mode 100644
index 00000000..49aa10f3
--- /dev/null
+++ b/docs/02-build-lab.md
@@ -0,0 +1,135 @@
+# SDD 02 — El laboratorio de build
+
+El laboratorio es la fábrica de artefactos: toma una **receta** (qué compilar y cómo) y
+produce un **árbol de archivos** depositado en el store, direccionado por su hash. Es la única
+parte del sistema que se permite ser funcional/determinista, porque es donde paga.
+
+## 1. Receta (`Recipe`)
+
+Una receta es una descripción declarativa y pura de *un* build. Es el átomo del grafo.
+
+```toml
+# ejemplo: recipes/grep.toml
+name        = "grep"
+version     = "3.11"
+
+[source]
+repo        = "git://git.savannah.gnu.org/grep.git"
+commit      = "a1b2c3d4e5f6..."        # FIJADO. Nunca "HEAD". Ver ADR 0006.
+patches     = ["patches/grep-perl-default.patch"]
+
+[build]
+compiler    = "zig-cc"                  # por defecto; escotilla: "clang" | "gcc"
+target      = "x86_64-linux-musl"
+link        = "static"                  # "static" | "dynamic"
+flags       = ["--enable-perl-regexp"]
+# fases override opcionales; si se omiten, se usan las heurísticas estándar
+# configure  = "..."  compile = "..."  install = "..."
+
+[deps]
+build       = ["pcre2", "musl"]         # dependencias de compilación (otras recetas)
+runtime     = []                        # vacío si link = static
+```
+
+El **compilador es por receta** (no global): `zig-cc` por defecto por hermeticidad y musl
+incluido, con escotilla a `clang`/`gcc` para paquetes con gcc-ismos. Ver
+[ADR 0003](adr/0003-zig-cc-builder.md).
+
+## 2. El identificador de contenido (CAS)
+
+Cada artefacto se direcciona por un hash que captura **todo** lo que influye en su salida:
+
+```
+artifact_hash = BLAKE3(
+      source_commit            // commit git fijado
+    ⧺ canonical(patches)       // contenido de los parches, no su ruta
+    ⧺ canonical(build_flags)   // flags + compilador + target + link
+    ⧺ Σ dep.artifact_hash      // hashes de las dependencias de build (recursivo)
+)
+```
+
+Consecuencia: **entrada idéntica ⇒ hash idéntico ⇒ salida idéntica**. Esto es lo que permite:
+
+- **Caché:** ¿el hash ya existe en el store? Se reusa, no se recompila.
+- **Avance ordenado del grafo:** si un upstream avanza su commit fijado, sólo cambian los
+  hashes de ese nodo y sus dependientes; el resto del grafo se reusa.
+- **Verificación de `.swm`:** dos máquinas con la misma receta producen el mismo hash; así se
+  verifica un cambio compartido sin confiar en binarios (ver [SDD 09](09-trust-model.md)).
+
+> BLAKE3 por velocidad y paralelismo; el hash no es un secreto, es un identificador.
+
+## 3. El sandbox de build
+
+Cada build corre en su propio entorno aislado, montado con **bubblewrap** (`bwrap`), que usa
+namespaces de Linux (mount, pid, net, user) sin requerir root real cuando el kernel lo permite.
+
+Receta del aislamiento:
+
+1. **Raíz tmpfs.** Se monta un `/` temporal vacío en tmpfs. Nada del host es visible salvo lo
+   que montemos explícitamente.
+2. **Compilador inyectado.** `zig` (o el compilador de la receta) se monta read-only en el
+   `PATH` del sandbox. En el bootstrap es el único compilador presente — así se rompe el
+   cordón umbilical con el host.
+3. **Fuentes read-only.** El árbol del repo (en el commit fijado) se monta read-only.
+4. **Dependencias read-only.** Los artefactos de las deps de build, ya en el store, se montan
+   read-only en rutas conocidas.
+5. **Sin red.** El namespace de red se aísla: el `fetch` ocurre *fuera* del sandbox (ver §4),
+   de modo que el build en sí no puede descargar nada no declarado → hermeticidad real.
+6. **Salida vía `DESTDIR`.** El build instala en `DESTDIR=/out`; ese árbol es el artefacto que
+   se extrae y se sella en el store.
+
+## 4. Fases del build
+
+Inspiradas en BitBake (`do_fetch`/`do_unpack`/`do_configure`/`do_compile`/`do_install`) pero
+mínimas. Sólo `fetch` toca la red, y ocurre **antes** de entrar al sandbox:
+
+| Fase | ¿En sandbox? | Qué hace |
+|---|---|---|
+| `fetch`     | No (red permitida) | Clona/actualiza el repo al commit fijado; verifica hash |
+| `patch`     | Sí | Aplica `source.patches` sobre el árbol read-only (en copia tmpfs) |
+| `configure` | Sí | Detecta sistema de build (autotools/cmake/meson/make) y configura |
+| `compile`   | Sí | Compila con el compilador de la receta hacia `target`/`link` |
+| `install`   | Sí | `make install DESTDIR=/out` (o equivalente) |
+| `seal`      | No | Calcula el hash final del árbol `/out`, lo deposita en el store |
+
+La detección de sistema de build en `configure` es heurística (presencia de `configure.ac`,
+`CMakeLists.txt`, `meson.build`, `Makefile`) y se puede sobreescribir por receta.
+
+## 5. El grafo de dependencias
+
+Las recetas forman un DAG por sus `deps.build`. El algoritmo de build:
+
+```
+build(recipe):
+    h = artifact_hash(recipe)          # requiere resolver deps primero (recursivo)
+    if store.has(h): return h          # caché
+    for dep in recipe.deps.build:
+        build(dep)                     # post-orden: deps antes que el nodo
+    sandbox = make_sandbox(recipe, deps)
+    run_phases(sandbox)                # patch → configure → compile → install
+    return store.seal(sandbox.out, h)
+```
+
+Builds de nodos independientes se paralelizan (sin dependencia mutua en el DAG). El cap de
+concurrencia se ajusta a los cores disponibles.
+
+## 6. Bootstrap (romper el cordón umbilical)
+
+El mayor error es usar las herramientas del host para compilar el sistema final. `zig cc`
+reduce drásticamente este problema: un solo binario provee compilador C/C++ + musl + headers,
+hermético, cross-compilando al target. El Stage 0 tradicional (cross-compiler mínimo) queda
+en gran parte resuelto por `zig`.
+
+Para la fase Alpine no necesitamos bootstrap completo: Alpine ya provee musl y un toolchain;
+usamos `zig cc` para los builds de hammer y validamos el flujo. El bootstrap from-scratch real
+es trabajo del track de distro propia ([SDD 10](10-roadmap.md), [ADR 0003](adr/0003-zig-cc-builder.md)).
+
+## 7. Interfaz (qué expone el crate)
+
+```rust
+// hammer-build
+pub fn build(recipe: &Recipe, store: &Store) -> Result<ArtifactHash>;
+pub fn artifact_hash(recipe: &Recipe, store: &Store) -> Result<ArtifactHash>;
+```
+
+CLI: `hammer build <recipe.toml>` → imprime el hash del artefacto sellado.
diff --git a/docs/03-hydration.md b/docs/03-hydration.md
new file mode 100644
index 00000000..634f5dba
--- /dev/null
+++ b/docs/03-hydration.md
@@ -0,0 +1,104 @@
+# SDD 03 — Hidratación y store
+
+La hidratación es el puente del sótano al piso de arriba: cómo un artefacto del store
+content-addressed termina siendo un `/bin/grep` normal, mutable, en un FHS clásico — sin
+arrastrar la ruta del store grabada a fuego, y sin el infierno de symlinks de Nix.
+
+## 1. El store
+
+```
+/store/<blake3>-<name>/        un artefacto sellado e inmutable
+    bin/grep
+    share/...
+```
+
+- **Inmutable y append-only.** Nada modifica un artefacto sellado. Reconstruir produce un
+  hash nuevo, una entrada nueva.
+- **Direccionado por contenido.** El prefijo es el `artifact_hash` (ver [SDD 02](02-build-lab.md)).
+- **Deduplicado.** Dos recetas que producen el mismo árbol comparten entrada.
+- **GC por alcanzabilidad.** Un artefacto es basura si ningún hardlink del FHS ni ningún pin
+  lo referencia. `hammer gc` libera lo inalcanzable.
+
+## 2. El problema que resolvemos
+
+Un binario compilado en un entorno funcional lleva grabado:
+
+- el **intérprete ELF** (el loader de la libc): p. ej. `/store/<hash>/lib/ld-musl-x86_64.so.1`,
+- el **RPATH** (dónde busca las `.so` dinámicas): rutas dentro del store.
+
+Si copias ese binario tal cual a `/bin`, falla: busca la libc en una ruta del store. Hay que
+**normalizar** las rutas al esquema clásico antes de que toque el FHS real.
+
+## 3. Estrategia primaria: enlazado estático (la vía limpia)
+
+Con musl, el camino de oro es **enlazar todo estáticamente** (`link = "static"`). El resultado
+es un único binario autosuficiente, sin `.so`, sin intérprete externo, sin RPATH que importe.
+
+- **Hidratar = hardlink directo** del binario del store a `/bin`/`/sbin`.
+- **Estructura familiar:** `/bin` real lleno de ejecutables normales; cero symlinks crípticos.
+- **Control total:** ¿reemplazar `ls` por una versión experimental compilada a mano? Copias el
+  binario encima y listo (ver §6, copy-on-write).
+
+Esta es la estrategia por defecto.
+
+## 4. Estrategia secundaria: purga de RPATH con `patchelf` (la vía dinámica)
+
+Cuando un paquete requiere enlazado dinámico (plugins, tooling específico), el lab compila
+contra el store, y la hidratación **reescribe el binario** antes de inyectarlo:
+
+1. `patchelf --set-interpreter /lib/ld-musl-x86_64.so.1 <bin>` — loader estándar del sistema.
+2. `patchelf --set-rpath /lib:/usr/lib <bin>` — rutas clásicas.
+3. Hardlink/copia del binario normalizado y de sus `.so` a `/lib`.
+
+`patchelf` (irónicamente, creado por el equipo de Nix) es la herramienta exacta para esto.
+
+## 5. El core dinámico curado (matiz honesto sobre el ABI de musl)
+
+La idea de "actualizar el sustrato atómicamente y que los binarios no se enteren" **sólo es
+segura si se versiona explícitamente.** musl **no garantiza estabilidad de ABI entre
+versiones**; confiar ciegamente en ello rompería binarios.
+
+Política de `hammer`:
+
+- El grueso del sistema se enlaza **estático** → inmune al problema.
+- Un subconjunto hiper-reducido de librerías core de actualización frecuente por seguridad
+  (p. ej. `openssl`, `zlib`) puede vivir **dinámico** en una ruta controlada `/lib/core/`,
+  **versionada** (`/lib/core/libssl.so.3`).
+- Las actualizaciones de ese core respetan el `soname`/versión. Si una actualización cambia el
+  ABI, **es un artefacto nuevo con soname nuevo**, no un reemplazo silencioso.
+- Para plugins reales, preferir `dlopen` versionado sobre fe en el ABI.
+
+Resultado: el superpoder de "reemplazar el suelo" existe, pero acotado y honesto, sin la
+promesa mágica que rompería en producción.
+
+## 6. Mutabilidad: copy-on-write sobre hardlinks
+
+El FHS está hidratado por **hardlinks** al store (no symlinks → rutas reales; no copias →
+dedup). El store es inmutable; el FHS es mutable. ¿Cómo conviven?
+
+- **Leer/ejecutar:** el hardlink apunta al inode del store. Cero copia.
+- **Escribir/pisar en caliente:** al reemplazar `/bin/grep`, **se rompe el hardlink** (se
+  escribe un inode nuevo). El artefacto del store queda intacto → base de rollback.
+- **Rollback:** re-hidratar desde el store restaura el hardlink original.
+
+Esto da exactamente lo buscado: "un `rm -rf` rompe cosas de verdad", pero siempre hay una base
+limpia reconstruible debajo.
+
+## 7. Interfaz
+
+```rust
+// hammer-core
+pub struct Store { root: PathBuf }
+impl Store {
+    pub fn has(&self, h: &ArtifactHash) -> bool;
+    pub fn seal(&self, out_dir: &Path, h: ArtifactHash) -> Result<PathBuf>;
+    pub fn path_of(&self, h: &ArtifactHash) -> PathBuf;
+    pub fn gc(&self, roots: &[ArtifactHash]) -> Result<GcReport>;
+}
+
+// hammer-build
+pub fn hydrate(h: &ArtifactHash, store: &Store, target_fhs: &Path, mode: LinkMode)
+    -> Result<Vec<HydratedFile>>;
+```
+
+CLI: `hammer hydrate <hash> [--into /]` — proyecta el artefacto al FHS (real o de overlay).
diff --git a/docs/04-overlay.md b/docs/04-overlay.md
new file mode 100644
index 00000000..952ded40
--- /dev/null
+++ b/docs/04-overlay.md
@@ -0,0 +1,78 @@
+# SDD 04 — Overlay de experimentación
+
+El overlay es la red de seguridad que convierte la mutabilidad total en algo que también es
+seguro: la capacidad de **cometer errores sin perder el control imperativo**. Es donde la IA
+prueba sus cambios antes de tocar el sistema real, y donde tú experimentas a mano sin miedo.
+
+## 1. El mecanismo
+
+Usa `overlayfs` nativo del kernel, gestionado dinámicamente desde la terminal:
+
+```
+                 montaje overlay sobre /bin (y /etc, /lib…)
+  upperdir  →  /var/lib/hammer/overlays/<id>/upper   (tmpfs o dir oculto, MUTABLE)
+  lowerdir  →  el /bin real                          (read-only de facto bajo el overlay)
+  merged    →  /bin                                  (lo que ve el sistema)
+```
+
+Mientras el overlay está montado, el sistema y tú veis `/bin` como **el sistema real
+modificado en caliente**. Pero toda escritura cae en el `upperdir`; el `/bin` real (lowerdir)
+nunca se toca.
+
+## 2. El ciclo de vida
+
+```
+hammer try            # monta un overlay sobre los directorios del sistema
+   ... experimentas / la IA inyecta binarios y edita configs ...
+   ... pruebas en caliente: ejecutas, rompes, observas ...
+hammer commit         # fusiona upperdir → FHS real (rsync inteligente) y registra en el diario
+   — o —
+hammer discard        # desmonta y borra el upperdir: el sistema vuelve al estado base, instantáneo
+```
+
+- **`try`** → estado base limpio + capa mutable encima. Riesgo cero.
+- **`discard`** → desmonta el overlay; el sistema vuelve a su base **instantáneamente**. No hay
+  que deshacer cambios uno por uno.
+- **`commit`** → fusiona la capa al FHS real y anota cada archivo tocado en el diario
+  ([SDD 05](05-journal.md)). A partir de aquí el cambio es permanente y rastreable.
+
+## 3. Por qué overlay y no contenedor
+
+Un contenedor (docker/chroot) te aísla de tus dispositivos y procesos reales — pierdes el
+acceso al sistema vivo. El overlay hace lo contrario: **modificas la "realidad" del sistema
+operativo** (mismos PIDs, mismos `/dev`, misma red) pero con una red de seguridad. Es la
+diferencia entre "probar en una maqueta" y "probar en la casa real con un seguro de vida".
+
+## 4. Composición con el resto del sistema
+
+- **La IA** (ver [SDD 08](08-ai-integration.md)) opera **siempre** dentro de un overlay: clona
+  el repo, compila en el lab, hidrata en el `upperdir`, edita configs en el `upper`. Tú validas
+  en caliente. La IA nunca escribe en el FHS real hasta que tú haces `commit`.
+- **Múltiples overlays** pueden coexistir (distintos `<id>`), p. ej. un experimento por
+  hipótesis. Cada uno es independiente.
+- **El diario** sólo registra en `commit` — el ruido del experimento no contamina la historia.
+
+## 5. Estados y reglas
+
+| Estado | Significado | Transiciones |
+|---|---|---|
+| `none` | sin overlay activo | `try` → `active` |
+| `active` | overlay montado, capa mutable encima | `commit` → `none` (+diario), `discard` → `none` |
+
+Reglas:
+- `commit`/`discard` sin overlay activo: no-op con aviso.
+- Un `try` anidado crea un overlay nuevo apilado; se desmontan en orden LIFO.
+- Si el sistema se apaga con overlays activos, al arranque `hammerd` los reporta y deja que el
+  humano decida (no auto-commit, no auto-discard — eso sería declarativo).
+
+## 6. Interfaz
+
+```rust
+// hammer-cli (con helpers de hammer-core)
+pub fn overlay_try(targets: &[PathBuf]) -> Result<OverlayId>;
+pub fn overlay_commit(id: OverlayId, journal: &Journal) -> Result<CommitReport>;
+pub fn overlay_discard(id: OverlayId) -> Result<()>;
+pub fn overlay_status() -> Result<Vec<OverlayState>>;
+```
+
+CLI: `hammer try` · `hammer commit` · `hammer discard` · `hammer status`.
diff --git a/docs/05-journal.md b/docs/05-journal.md
new file mode 100644
index 00000000..55189f2c
--- /dev/null
+++ b/docs/05-journal.md
@@ -0,0 +1,86 @@
+# SDD 05 — Diario de mutaciones
+
+Este es el insight central de `hammer`: **el diario es tu configuración del sistema — sin ser
+declarativa.** No declaras tu sistema en un archivo de texto antes de vivirlo; vives el sistema
+imperativamente, y el propio sistema deriva, *a posteriori*, un mapa de tu desviación respecto
+a la base limpia construida por el laboratorio.
+
+Esto rompe la falsa dicotomía declarativo vs imperativo, y resuelve dos problemas a la vez:
+
+- El de Arch/Gentoo: con los meses se pudren en archivos huérfanos porque el gestor pierde el
+  rastro de lo que el usuario hizo a mano.
+- El de Nix: para evitar lo anterior, te ata las manos (todo debe declararse antes).
+
+## 1. El mecanismo
+
+Un daemon ultraligero (`hammerd`) usa **`fanotify`** a nivel de kernel para registrar
+**exclusivamente las mutaciones** sobre los directorios del sistema (`/bin`, `/sbin`, `/lib`,
+`/etc`). No bloquea ninguna acción. Te deja destruir, mover y crear archivos a tu antojo. Pero
+anota, en silencio, un diario de modificaciones.
+
+> `fanotify` sobre `inotify`: cobertura a nivel de superbloque/mount, eventos de modificación
+> con info de PID/UID, y menor coste que vigilar recursivamente cada subdirectorio.
+
+## 2. Qué registra (y qué no)
+
+**Registra** mutaciones del FHS gestionado:
+
+- creación / reemplazo / borrado de archivos en `/bin`, `/sbin`, `/lib`, `/etc`,
+- qué los originó (PID, UID, y si fue una hidratación de `hammer`, el `artifact_hash`),
+- ediciones de archivos de config en `/etc`.
+
+**No registra:**
+
+- actividad efímera en `/tmp`, `/run`, `/proc`, `/sys`, `/dev`,
+- lecturas/ejecuciones (sólo mutaciones),
+- nada dentro de un overlay activo (el ruido del experimento no entra; sólo el `commit`).
+
+## 3. Formato del diario
+
+Log **append-only de texto plano** (JSON-líneas), legible con `cat`/`grep`/`jq`. Cada línea es
+un evento atómico. (Los timestamps los provee el daemon; el formato no impone reloj de
+construcción.)
+
+```jsonl
+{"ts":"2026-06-06T18:40:01Z","op":"replace","path":"/bin/grep","by":{"uid":1000,"pid":4821},"artifact":"b3:9f2a…","note":"hydrate grep@perl-default"}
+{"ts":"2026-06-06T18:41:12Z","op":"edit","path":"/etc/network.conf","by":{"uid":1000,"pid":4990},"diff_hash":"b3:7c1d…"}
+{"ts":"2026-06-06T18:42:03Z","op":"manual-replace","path":"/bin/ls","by":{"uid":1000,"pid":5102},"artifact":null,"note":"usuario pisó ls a mano"}
+```
+
+`artifact: null` + `op: manual-replace` ⇒ el usuario reemplazó algo a mano fuera del flujo de
+`hammer`. Eso no es un error; es información. El diario distingue "mutación trazable" (vino de
+una receta/artefacto conocido) de "mutación opaca" (pisada manual), sin prohibir ninguna.
+
+## 4. Exportar: del diario al `.swm`
+
+`hammer export` lee el diario, lo recorta al delta relevante respecto a una **base** conocida,
+y produce un manifiesto `.swm` ([SDD 06](06-swm-format.md)):
+
+- **base** = el conjunto de commits fijados + versión de distro de los que partiste.
+- **mutations** = las mutaciones trazables convertidas a recetas (`source_patch`) y las
+  ediciones de config (`config_edit`), más reglas de init si aplican.
+- Las mutaciones **opacas** (pisadas manuales sin artefacto) se reportan como advertencia: no
+  se pueden compartir como receta reproducible. `hammer` te dice exactamente cuáles y por qué.
+
+Así, **exportar el diario = exportar tu distro**, pero sólo la parte que es reproducible y
+verificable. Lo que pisaste a ciegas, lo sabes y decides qué hacer con ello.
+
+## 5. Replicar en otra máquina
+
+No copias una config abstracta: exportas el diario de tus acciones humanas sobre el metal. La
+otra máquina, partiendo de la misma base, **reproduce** las recetas y aplica las ediciones.
+Tu sistema se replica desde su historia, no desde una declaración.
+
+## 6. Interfaz
+
+```rust
+// hammerd / hammer-core
+pub struct Journal { path: PathBuf }
+impl Journal {
+    pub fn record(&self, ev: MutationEvent) -> Result<()>;
+    pub fn since(&self, base: &BaseRef) -> Result<Vec<MutationEvent>>;
+    pub fn export_swm(&self, base: &BaseRef) -> Result<(Swm, Vec<OpaqueWarning>)>;
+}
+```
+
+CLI: `hammer journal` (ver/seguir el diario) · `hammer export [--base <ref>] > my.swm`.
diff --git a/docs/06-swm-format.md b/docs/06-swm-format.md
new file mode 100644
index 00000000..32ca690c
--- /dev/null
+++ b/docs/06-swm-format.md
@@ -0,0 +1,113 @@
+# SDD 06 — Formato `.swm` (Software Mutación)
+
+El `.swm` es la unidad de intercambio de `hammer`. **No es un paquete binario** (`.deb`,
+`.rpm`, ni un `PKGBUILD` que compila quién-sabe-qué). Es un **manifiesto de la mutación**: la
+receta de transformación sobre código fuente público, más las ediciones de configuración. El
+receptor reproduce y verifica localmente; **nunca ejecuta tu binario** (ver
+[SDD 09](09-trust-model.md)).
+
+## 1. Esquema
+
+```yaml
+# my-grep-tweak.swm
+swm_version: 1
+
+base:
+  distro_version: "2026-06-06"      # versión del set base de hammer
+  pins:                              # commits fijados de los upstreams relevantes
+    kernel: "a1b2c3d…"
+    musl:   "e4f5a6b…"
+  # base_hash deriva de pins+distro_version; el receptor verifica compatibilidad
+
+mutations:
+  - type: source_patch              # recompilar una herramienta desde su fuente parcheada
+    repo: "git://git.savannah.gnu.org/grep.git"
+    commit: "a1b2c3d…"              # commit fijado sobre el que aplica el patch
+    patch: |                         # parche .patch de git, embebido o por URL (patch_url)
+      --- a/src/main.c
+      +++ b/src/main.c
+      @@ ...
+    build:
+      compiler: "zig-cc"
+      target: "x86_64-linux-musl"
+      link: "static"
+      flags: ["--enable-perl-regexp"]
+    target_bin: "/bin/grep"
+
+  - type: config_edit               # editar un archivo de config en texto plano
+    file: "/etc/network.conf"
+    inline_diff: |
+      - DHCP=yes
+      + IP=192.168.1.100
+
+  - type: init_rule                 # añadir/ajustar una regla del init (ver SDD 07)
+    action: "watchdog"
+    service: "web"
+    command: "/bin/myweb -p 8080"
+
+signature:                           # opcional pero recomendado (ver SDD 09)
+  by: "sergio"
+  alg: "ed25519"
+  sig: "base64…"
+```
+
+## 2. Tipos de mutación
+
+| `type` | Qué describe | Cómo lo aplica el receptor |
+|---|---|---|
+| `source_patch` | recompilar una herramienta desde fuente parcheada | clona repo@commit → aplica patch → `hammer build` → hidrata en overlay |
+| `config_edit` | edición de un archivo de config | aplica el `inline_diff` (3-way) sobre el archivo objetivo |
+| `init_rule` | regla del bus de init | inyecta la regla vía `/run/init.control` / receta de servicio |
+| `file_drop` | depositar un archivo de datos no compilable | escribe el archivo (con su hash declarado) en la ruta |
+
+Cada `source_patch` es, en esencia, una `Recipe` ([SDD 02](02-build-lab.md)) serializada para
+viajar. El `build` lleva el **compilador por mutación** (no global).
+
+## 3. Aplicación (`hammer apply`)
+
+```
+hammer apply my-grep-tweak.swm
+```
+
+1. **Verifica la base.** ¿Los `pins`/`distro_version` son compatibles con el sistema local?
+   Si no, avisa qué difiere y se detiene (o `--force` bajo tu responsabilidad).
+2. **Verifica la firma** (si existe) contra las claves de confianza locales.
+3. **Reproduce.** Para cada `source_patch`: clona el repo al commit, aplica el patch, compila
+   en el lab local → obtiene un `artifact_hash`.
+4. **Aísla.** Hidrata todo en un **overlay temporal** ([SDD 04](04-overlay.md)); aplica
+   `config_edit`/`init_rule`/`file_drop` en esa capa. **No toca el sistema base.**
+5. **Valida.** Corres/pruebas en caliente. Si bien → `hammer commit`. Si mal → `hammer discard`.
+
+Nunca se ejecuta un binario ajeno: sólo se transforma código fuente público con una receta que
+tu propio laboratorio compila.
+
+## 4. Determinismo y verificación cruzada
+
+Como el lab es determinista ([SDD 02](02-build-lab.md)), el `artifact_hash` que produce tu
+máquina debe coincidir con el del autor (si declara `expected_hash`). Coincidencia ⇒ obtuviste
+exactamente el mismo binario, sin haberlo descargado. Discrepancia ⇒ algo difiere (toolchain,
+pin, patch) y `hammer` te dice qué. Esto es "verificar, no confiar" en la práctica.
+
+## 5. No-objetivos del formato
+
+- **No** transporta binarios cocidos (salvo `file_drop` para datos no compilables, con hash).
+- **No** es Turing-completo: es declarativo *para el intercambio*, aunque el sistema que
+  describe se viva imperativamente. (Lo declarativo aquí es honesto: describe una
+  transformación, no aprisiona tu sistema.)
+- **No** asume una arquitectura: `target` viaja en cada `source_patch`.
+
+## 6. Interfaz
+
+```rust
+// hammer-core
+#[derive(Serialize, Deserialize)]
+pub struct Swm { /* swm_version, base, mutations, signature */ }
+impl Swm {
+    pub fn from_yaml(s: &str) -> Result<Swm>;
+    pub fn to_yaml(&self) -> Result<String>;
+    pub fn verify_base(&self, local: &BaseRef) -> BaseCompat;
+    pub fn verify_signature(&self, trust: &TrustStore) -> SigStatus;
+}
+```
+
+CLI: `hammer apply <file.swm>` · `hammer export … > out.swm` · `hammer swm verify <file.swm>`.
diff --git a/docs/07-agent-bus.md b/docs/07-agent-bus.md
new file mode 100644
index 00000000..7ddcc80b
--- /dev/null
+++ b/docs/07-agent-bus.md
@@ -0,0 +1,98 @@
+# SDD 07 — Bus de init y de agente
+
+El sistema se controla por **tuberías UNIX puras**, no por parseo de archivos `.service`
+complejos. Hay dos canales, con propósitos distintos:
+
+1. **`/run/init.control`** — FIFO de control **humano**, texto crudo. Ergonomía máxima.
+2. **`/run/agent.sock`** — socket de control de **agente** (IA, scripts), JSON-líneas con
+   framing y autenticación. Parseable y fiable.
+
+## 1. El init por eventos UNIX
+
+Tu init no lee configuraciones pesadas: expone una API por FIFO. Cualquier proceso —un script,
+un binario, o tú tecleando— controla el estado del sistema enviando bytes crudos:
+
+```sh
+echo "restart network" > /run/init.control
+echo "start web"       > /run/init.control
+echo "stop  web"       > /run/init.control
+```
+
+Los servicios no se declaran en archivos pesados; se **inyectan dinámicamente**. El estado del
+sistema es un flujo vivo y maleable que manipulas con herramientas estándar (`cat`, `echo`,
+`grep`). Los servicios viven como directorios con un script `run` ejecutable (estilo s6/runit),
+no como unidades declarativas opacas:
+
+```
+/etc/service/web/run        # script ejecutable; el init lo supervisa
+/etc/service/network/run
+```
+
+## 2. Por qué un segundo canal para la IA
+
+El FIFO crudo es perfecto para humanos pero malo como API de máquina: no tiene framing fiable,
+ni forma de devolver eventos correlacionados, ni de saber **quién** habla. La IA necesita:
+
+- enviar comandos estructurados y recibir **eventos** correlacionados (éxito/fallo de un build,
+  crash de un servicio),
+- **autenticación** del peer (que no cualquier proceso dispare builds o inyecte binarios),
+- un protocolo pequeño, legible y versionado.
+
+Por eso `/run/agent.sock` es un socket UNIX con:
+
+- **framing** = JSON-líneas (un objeto JSON por línea, `\n`-terminado),
+- **auth** = `SO_PEERCRED` (UID/GID/PID del peer verificados por el kernel) + capacidades que
+  el humano concede explícitamente (ver [SDD 08](08-ai-integration.md)),
+- **versión** en el handshake.
+
+## 3. Protocolo del bus de agente
+
+### Handshake
+
+```json
+{"t":"hello","ver":1,"client":"claude-agent"}
+{"t":"welcome","ver":1,"caps":["compile","query"]}   // caps según lo que el humano concedió
+```
+
+### Comandos (cliente → hammerd)
+
+| Comando | Forma | Efecto |
+|---|---|---|
+| `COMPILE` | `{"t":"compile","recipe":{…}}` o `{"repo","commit","patch","build"}` | dispara un build en el lab |
+| `INJECT` | `{"t":"inject","artifact":"b3:…","target":"/bin/grep","overlay":"<id>"}` | hidrata en un overlay (o real si hay cap) |
+| `QUERY` | `{"t":"query","what":"file","path":"/etc/network.conf"}` | estado de un archivo/servicio/artefacto |
+| `INIT` | `{"t":"init","cmd":"start web"}` | proxy autenticado al control del init |
+
+### Eventos (hammerd → cliente)
+
+| Evento | Forma | Significado |
+|---|---|---|
+| `BUILD_READY` | `{"t":"build_ready","artifact":"b3:…","recipe":"grep"}` | build terminó OK |
+| `BUILD_FAILED` | `{"t":"build_failed","recipe":"grep","log_tail":"…"}` | build falló, con cola de log |
+| `CRASHED` | `{"t":"crashed","service":"web","code":127}` | un servicio supervisado murió |
+| `MODIFIED` | `{"t":"modified","path":"/bin/grep","by":{…}}` | el diario registró una mutación |
+
+Ejemplo del bucle de autorreparación: la IA modifica el binario del servidor web, este falla
+al arrancar; `hammerd` emite `{"t":"crashed","service":"web","code":127}`; la IA, escuchando,
+lee el log (texto plano en `/var/log`), corrige la fuente, recompila, y reenvía `start web`.
+Para el humano, el sistema "se autorreparó" — pero cada paso quedó en el bus y en el diario.
+
+## 4. Seguridad del bus
+
+- **Sin auth, sin comandos.** Conexión que no completa `hello` válido se cierra.
+- **Capacidades mínimas.** Por defecto un agente sólo obtiene `query`. `compile`, `inject` (a
+  overlay) e `inject-real` (al FHS real) se conceden explícita y separadamente.
+- **`inject-real` es especial.** Inyectar al sistema real (no a overlay) requiere una capacidad
+  aparte y, por política, confirmación humana. El flujo recomendado de la IA es siempre overlay
+  + `commit` humano.
+- **Todo comando con efecto se registra** (en el diario y/o un audit log del bus).
+
+## 5. Interfaz
+
+```rust
+// hammerd
+pub async fn serve_agent_bus(sock: &Path, caps_policy: CapsPolicy) -> Result<()>;
+pub fn init_control_send(line: &str) -> Result<()>;   // escribe en /run/init.control
+```
+
+CLI de conveniencia: `hammer ctl "start web"` (humano) · la IA usa el socket directamente.
diff --git a/docs/08-ai-integration.md b/docs/08-ai-integration.md
new file mode 100644
index 00000000..76525b76
--- /dev/null
+++ b/docs/08-ai-integration.md
@@ -0,0 +1,113 @@
+# SDD 08 — Integración de la IA
+
+La IA es un **artesano hiperveloz en el taller**; el humano es **el dueño que decide si el
+mueble entra a la casa o se va a la basura.** Esta sección define el bucle agéntico, sus
+garantías de seguridad, y cómo una intención en lenguaje natural se vuelve un cambio real.
+
+## 1. La terminal como runtime de la IA
+
+La IA no es un chat en una ventana que te dice qué teclear. Opera directamente sobre el sistema
+a través del **bus de agente** ([SDD 07](07-agent-bus.md)) y de un **overlay**
+([SDD 04](04-overlay.md)). Su entorno de trabajo es el sistema real, con red de seguridad.
+
+## 2. El bucle agéntico
+
+```
+   intención (NL)
+        │  "que grep ignore binarios por defecto y use regex Perl,
+        │   y que la red use IP estática 192.168.1.100"
+        ▼
+   ┌─────────────┐
+   │  PLAN        │  la IA traduce la intención a un .swm: qué herramienta,
+   │              │  qué patch de fuente, qué flags, qué config editar
+   └──────┬──────┘
+          ▼
+   ┌─────────────┐
+   │  BUILD       │  COMPILE por el bus → el lab clona repo@commit, aplica patch,
+   │  (lab)       │  compila estático con zig cc → artifact_hash
+   └──────┬──────┘
+          ▼
+   ┌─────────────┐
+   │  TRY         │  hammer try → overlay temporal; INJECT del artefacto y de las
+   │  (overlay)   │  ediciones de config en la capa. El sistema real intacto.
+   └──────┬──────┘
+          ▼
+   ┌─────────────┐
+   │  VERIFY      │  corre el test harness; escucha BUILD_FAILED / CRASHED por el bus.
+   │              │  si falla → corrige fuente → recompila (vuelve a BUILD).
+   └──────┬──────┘
+          ▼
+   ┌─────────────┐
+   │  PROPOSE     │  la IA avisa: "listo, probé esto, aquí el diff y el resultado".
+   │              │  presenta el .swm y la evidencia.
+   └──────┬──────┘
+          ▼
+   ┌─────────────┐
+   │  HUMANO      │  tú decides: hammer commit (promueve + diario) o hammer discard.
+   │  decide      │  La IA NUNCA promueve al FHS real por su cuenta (ver §4).
+   └─────────────┘
+```
+
+## 3. Por qué esta arquitectura se presta (y otras no)
+
+- **Determinismo del lab** → la IA puede recompilar y volver atrás sin dramas; el resultado es
+  predecible.
+- **Texto plano + binarios atómicos** → la IA lee/escribe archivos e inspecciona binarios con
+  `readelf`/`objdump`; no parsea bases de datos opacas.
+- **musl legible** → el código C de la libc base es comprensible en el contexto de un LLM
+  (glibc es un laberinto de macros).
+- **Enlazado estático** → una herramienta mutada corre sin romper enlaces de otros programas.
+- **Mutabilidad + overlay** → agencia real con red de seguridad; sin rollbacks pesados.
+
+En distros inmutables/declarativas, la IA tendría que lidiar con generadores de config y
+políticas read-only; en tradicionales, no tendría provenance. `hammer` mantiene las **tuberías
+expuestas y de baja entropía**, que es justo lo que un agente necesita.
+
+## 4. Garantías de seguridad (no negociables)
+
+1. **La IA trabaja en overlay por defecto.** Sin capacidad `inject-real`, no puede tocar el
+   FHS base. El flujo es siempre overlay → `commit` humano.
+2. **Capacidades mínimas y explícitas.** El humano concede `query`/`compile`/`inject` por
+   separado vía la política del bus ([SDD 07](07-agent-bus.md)).
+3. **Toda acción es reversible y registrada.** `discard` revierte el overlay; el `commit`
+   entra al diario firmado ([SDD 05](05-journal.md)).
+4. **Recetas, no binarios.** La IA produce `.swm` (fuente + flags + config), no binarios
+   opacos. Lo que comparte es verificable por terceros ([SDD 06](06-swm-format.md)).
+5. **El humano tiene la última palabra.** Ningún cambio se vuelve permanente sin `commit`.
+
+## 5. De la intención al `.swm`: el rol del modelo
+
+El traductor intención→`.swm` es un LLM. Detalles de modelo/API (Claude, herramientas, prompts)
+se documentarán aparte cuando se implemente la Fase 6; aquí sólo fijamos el contrato:
+
+- **Entrada:** intención en NL + contexto del sistema (qué herramientas hay, qué pins, estado
+  de servicios — todo consultable por `QUERY`).
+- **Salida:** un `.swm` válido ([SDD 06](06-swm-format.md)) + un plan de verificación.
+- **El modelo no ejecuta nada directamente:** emite comandos por el bus, que `hammerd` valida
+  contra las capacidades concedidas.
+
+## 6. Lenguaje de consulta/transformación (visión, Fase posterior)
+
+Para que la IA refiera partes del sistema sin rutas absolutas frágiles, un mini-lenguaje de
+consulta sobre el grafo del sistema:
+
+```
+find /service/web -where "depends_on(libssl)" -> replace_with my_tls
+```
+
+El daemon traduce esa consulta estructurada a acciones reales del bus. La terminal sigue siendo
+el lugar de validación final. Esto es visión, no Fase 0 — se diseñará cuando el bucle básico
+esté probado.
+
+## 7. Interfaz
+
+```rust
+// cliente del bus (puede vivir en un crate aparte hammer-agent en Fase 6)
+pub trait AgentClient {
+    fn hello(&mut self) -> Result<Caps>;
+    fn compile(&mut self, recipe: &Recipe) -> Result<ArtifactHash>;
+    fn inject(&mut self, h: &ArtifactHash, target: &Path, overlay: OverlayId) -> Result<()>;
+    fn query(&mut self, q: Query) -> Result<QueryResult>;
+    fn events(&mut self) -> impl Iterator<Item = BusEvent>;
+}
+```
diff --git a/docs/09-trust-model.md b/docs/09-trust-model.md
new file mode 100644
index 00000000..7667a65c
--- /dev/null
+++ b/docs/09-trust-model.md
@@ -0,0 +1,96 @@
+# SDD 09 — Modelo de confianza
+
+La premisa de compartir en `hammer` es **"verificar, no confiar"**: nunca ejecutas un binario
+ajeno; reproduces una receta sobre código fuente público y compruebas que obtienes el mismo
+resultado. Esto sólo funciona si el build es determinista y si el intercambio está firmado y,
+opcionalmente, anclado a un log de transparencia.
+
+## 1. La cadena de confianza
+
+```
+   código fuente público (repo@commit fijado)
+        │  +  patch declarado en el .swm
+        ▼
+   build determinista en TU laboratorio local
+        │  →  artifact_hash reproducible
+        ▼
+   ¿coincide con el expected_hash del autor?
+        ├─ sí  → obtuviste exactamente su binario, sin descargarlo. Confianza derivada del código, no del autor.
+        └─ no  → algo difiere (pin, patch, toolchain). hammer te dice qué. No promueves.
+```
+
+El binario del autor **nunca viaja**. Viaja la *receta*. La confianza no está en "el binario de
+sergio es bueno", sino en "el código fuente público + esta transformación produce esto, y lo
+verifiqué yo mismo".
+
+## 2. Determinismo como cimiento
+
+Todo esto descansa en que dos máquinas con la misma entrada produzcan el mismo
+`artifact_hash` ([SDD 02](02-build-lab.md)). Requisitos prácticos de reproducibilidad:
+
+- **Toolchain fijado.** El `zig`/compilador y su versión forman parte del hash de entrada.
+- **Commits fijados.** Nada de `HEAD` ([ADR 0006](adr/0006-pinned-commits.md)).
+- **Sandbox hermético.** Sin red durante el build, sin fugas del host
+  ([SDD 02](02-build-lab.md) §3).
+- **Eliminación de no-determinismo.** Timestamps embebidos, rutas absolutas, orden de archivos,
+  paralelismo no determinista → se normalizan (p. ej. `SOURCE_DATE_EPOCH`, orden estable).
+
+Cuando un build no reproduce, es un **bug a corregir**, no una excepción a tolerar. La
+reproducibilidad bit-a-bit es objetivo, no aspiración.
+
+## 3. Firma del `.swm`
+
+Un `.swm` puede ir firmado (Ed25519). La firma cubre el contenido del manifiesto (base +
+mutations). Sirve para:
+
+- **Autoría:** saber quién publicó la receta.
+- **Integridad:** que no se alteró en tránsito.
+
+La firma **no** sustituye la verificación reproducible — un autor firmado podría declarar un
+`expected_hash` que no corresponde a su patch; por eso `hammer apply` **siempre** reproduce y
+compara, firme o no.
+
+## 4. Log de transparencia (visión, opt-in)
+
+Para compartir en comunidad sin un repositorio central de binarios de confianza, los `.swm`
+publicados pueden anclarse a un **log de transparencia append-only** (estilo Sigstore/Rekor):
+
+- cada `.swm` publicado deja una entrada inmutable (hash del manifiesto + firma + timestamp),
+- cualquiera puede auditar la historia: qué se publicó, por quién, cuándo,
+- detecta sustituciones silenciosas y "split-view".
+
+Esto es opt-in y de fase posterior; el modelo base (reproducir + firmar) ya da la garantía
+fuerte: **no ejecutas binarios ajenos**.
+
+## 5. TrustStore local
+
+Claves públicas en las que el usuario confía para *autoría* (no para ejecución):
+
+```
+/var/lib/hammer/trust/
+    sergio.ed25519.pub
+    comunidad-foo.ed25519.pub
+```
+
+`hammer apply` reporta el estado de firma (`trusted` / `unknown-key` / `bad-sig` / `unsigned`)
+pero la decisión de promover sigue dependiendo de la **verificación reproducible** + el
+`commit` humano.
+
+## 6. Resumen de garantías
+
+| Amenaza | Mitigación |
+|---|---|
+| Ejecutar binario ajeno malicioso | No se ejecutan binarios ajenos; se reproduce desde fuente |
+| Receta alterada en tránsito | Firma Ed25519 del `.swm` |
+| Build no reproducible / backdoor en toolchain | Toolchain fijado en el hash + determinismo verificado |
+| Sustitución silenciosa en la comunidad | Log de transparencia (opt-in) |
+| Promoción accidental de algo malo | Overlay + `commit` humano explícito |
+
+## 7. Interfaz
+
+```rust
+// hammer-core
+pub fn sign_swm(swm: &Swm, key: &Ed25519PrivateKey) -> Signature;
+pub fn verify_swm(swm: &Swm, trust: &TrustStore) -> SigStatus;
+pub fn reproduce_and_compare(swm: &Swm, store: &Store) -> Result<Vec<HashMatch>>;
+```
diff --git a/docs/10-roadmap.md b/docs/10-roadmap.md
new file mode 100644
index 00000000..a08be105
--- /dev/null
+++ b/docs/10-roadmap.md
@@ -0,0 +1,80 @@
+# SDD 10 — Roadmap
+
+## Estrategia: validar la capa AI-nativa sobre Alpine antes de la distro propia
+
+La innovación de `hammer` no es la distro — es el substrato AI-nativo (build determinista +
+mutable + diario + `.swm`). Construir bootstrap + init + userland de cero antes de validar esa
+capa sería arriesgar meses contra una hipótesis no probada. Por eso:
+
+> **Fase 0–6:** montamos `hammer` **sobre Alpine** (musl + busybox + FHS mutable, ya cocidos).
+> Validamos el bucle completo en semanas.
+> **Track posterior:** una vez probado, bajamos a distro propia (init propio, bootstrap propio,
+> userland propio) reusando todo el tooling sin retrabajo.
+
+Ver [ADR 0002](adr/0002-alpine-first.md).
+
+---
+
+## Fases (sobre Alpine)
+
+### Fase 0 — Laboratorio de build  ▶ *empezamos aquí*
+- [ ] `hammer-core`: tipos `Recipe`, `ArtifactHash`, `Store` (BLAKE3, layout `/store`).
+- [ ] `hammer-build`: sandbox con `bubblewrap` + `zig cc` → binario musl estático.
+- [ ] CAS: hashing de entrada, caché por hash, sellado en el store.
+- [ ] `hammer build <recipe.toml>` → imprime el hash del artefacto.
+- **Hecho cuando:** una receta compila reproduciblemente y queda en el store.
+
+### Fase 1 — Hidratación
+- [ ] `hydrate(hash, target, mode)`: hardlink a FHS, `patchelf` para el caso dinámico.
+- [ ] `hammer hydrate <hash> --into /`.
+- **Hecho cuando:** un artefacto del store aparece como `/bin/<x>` real y ejecutable.
+
+### 🎯 Primer entregable (Fase 0 + 1)
+**Compilar `grep` estático desde su repo con un patch, hidratarlo a `/bin/grep`, y que corra**,
+todo dentro de una VM/LXC Alpine. Esto prueba el corazón "fábrica funcional → FHS mutable".
+
+### Fase 2 — Overlay de experimentación
+- [ ] `try` / `commit` / `discard` / `status` sobre `overlayfs`.
+- **Hecho cuando:** puedes romper `/bin` en un overlay y revertir con `discard`.
+
+### Fase 3 — Diario de mutaciones
+- [ ] `hammerd` con `fanotify` sobre `/bin`,`/sbin`,`/lib`,`/etc`.
+- [ ] Log JSON-líneas append-only; `hammer journal`.
+- **Hecho cuando:** toda mutación trazable/opaca queda registrada y consultable.
+
+### Fase 4 — Formato y flujo `.swm`
+- [ ] `Swm` (de/serialización YAML), `hammer export`, `hammer apply` (con overlay), `verify`.
+- **Hecho cuando:** exportas un cambio, lo aplicas en otra máquina y reproduce idéntico.
+
+### Fase 5 — Bus de agente
+- [ ] `/run/init.control` (FIFO humano) + `/run/agent.sock` (JSON-líneas, `SO_PEERCRED`).
+- [ ] Comandos `COMPILE`/`INJECT`/`QUERY`/`INIT`; eventos `BUILD_*`/`CRASHED`/`MODIFIED`.
+- **Hecho cuando:** un cliente externo dispara un build y recibe el evento de fin por el socket.
+
+### Fase 6 — Integración de la IA
+- [ ] Cliente de agente; traductor intención NL → `.swm`; bucle plan→build→try→verify→propose.
+- **Hecho cuando:** una intención en lenguaje natural produce un cambio probado en overlay,
+  presentado para `commit` humano.
+
+---
+
+## Track posterior — distro propia
+- Reemplazar el init de Alpine por **tu init** (bus por pipes nativo).
+- **Bootstrap from-scratch** con `zig`/`musl-cross-make` (Stage 0/1/2 → imagen destino).
+- Userland propio (busybox/toybox a elección), `/etc/service/*` propios.
+- Decidir particionado/montaje de `/store` y `/var/lib/hammer`.
+- Log de transparencia para compartir en comunidad ([SDD 09](09-trust-model.md) §4).
+- Mini-lenguaje de consulta del sistema para la IA ([SDD 08](08-ai-integration.md) §6).
+
+---
+
+## Estado actual
+- ✅ Repo y workspace Rust inicializados.
+- ✅ SDDs y ADRs redactados.
+- ✅ Esqueletos de crates que compilan (`hammer build` stub).
+- ⏭️ Siguiente: implementar el sandbox de build real (Fase 0) y montar la VM/LXC Alpine.
+
+## Notas de entorno
+- Desarrollo principal: laptop del autor.
+- Host actual: Proxmox (`gioser.net`). La VM/LXC Alpine de pruebas vivirá aquí o en la laptop.
+- Repo: `https://gitea.gioser.net/sergio/hammer`.
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..61771976
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,33 @@
+# Documentación de diseño de hammer
+
+Estos documentos son la fuente de verdad del diseño. El código los implementa; cuando haya
+discrepancia, o se corrige el código o se actualiza el SDD con un commit que explique por qué.
+
+## Software Design Documents (SDD)
+
+| # | Documento | Qué cubre |
+|---|---|---|
+| 00 | [Visión y filosofía](00-vision.md) | Por qué existe, qué problema resuelve, la actitud de ingeniería |
+| 01 | [Arquitectura general](01-architecture.md) | El modelo de dos mundos, componentes, flujo de datos |
+| 02 | [El laboratorio de build](02-build-lab.md) | Sandbox, `zig cc`, recetas, CAS, grafo de dependencias |
+| 03 | [Hidratación y store](03-hydration.md) | Store content-addressed, hardlinks a FHS, patchelf, rollback |
+| 04 | [Overlay de experimentación](04-overlay.md) | overlayfs en caliente, try/commit/discard |
+| 05 | [Diario de mutaciones](05-journal.md) | fanotify, log append-only, config-sin-ser-declarativa |
+| 06 | [Formato `.swm`](06-swm-format.md) | Manifiesto de mutación compartible, esquema, firma |
+| 07 | [Bus de init y de agente](07-agent-bus.md) | `/run/init.control`, `/run/agent.sock`, protocolo |
+| 08 | [Integración de la IA](08-ai-integration.md) | El bucle agéntico, seguridad, intención → `.swm` |
+| 09 | [Modelo de confianza](09-trust-model.md) | Reproducibilidad, verificar-no-confiar, log de transparencia |
+| 10 | [Roadmap](10-roadmap.md) | Fases, MVP, primer entregable |
+
+## Architecture Decision Records (ADR)
+
+Decisiones tomadas, con su contexto y consecuencias. Ver [`adr/`](adr/).
+
+| # | Decisión |
+|---|---|
+| 0001 | [Rust para el tooling y daemons](adr/0001-rust-for-tooling.md) |
+| 0002 | [Validar sobre Alpine antes de la distro propia](adr/0002-alpine-first.md) |
+| 0003 | [`zig cc` como compilador por defecto del lab](adr/0003-zig-cc-builder.md) |
+| 0004 | [No escribir nuestro propio Nix](adr/0004-no-custom-nix.md) |
+| 0005 | [Hidratación por hardlinks](adr/0005-hardlink-hydration.md) |
+| 0006 | [Commits fijados, no HEAD vivo](adr/0006-pinned-commits.md) |
diff --git a/docs/adr/0001-rust-for-tooling.md b/docs/adr/0001-rust-for-tooling.md
new file mode 100644
index 00000000..eebfd72a
--- /dev/null
+++ b/docs/adr/0001-rust-for-tooling.md
@@ -0,0 +1,30 @@
+# ADR 0001 — Rust para el tooling y los daemons
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+Necesitamos un lenguaje para `hammerd`, las CLIs y el daemon del diario. Candidatos: Rust, Go,
+Zig. El sistema manipula ELF, sockets UNIX, `fanotify`, `overlayfs`, namespaces, y produce
+binarios que deben correr en un userland musl, posiblemente estáticos.
+
+## Decisión
+
+**Rust** para todo el tooling y los daemons.
+
+## Razones
+
+- **Binarios estáticos-musl** de primera (`x86_64-unknown-linux-musl`), justo nuestro target.
+- Ecosistema fuerte para lo que hacemos: parsing/edición ELF, sockets, `nix`/`rustix` para
+  syscalls (`fanotify`, namespaces), `blake3`, `serde`.
+- Seguridad de memoria sin GC; importante en un daemon de larga vida con privilegios.
+- El autor lo eligió explícitamente.
+
+## Consecuencias
+
+- Curva de entrada más alta que Go; asumida.
+- Compilación del compilador del lab es **ortogonal**: escribimos `hammer` en Rust, el lab
+  invoca `zig cc` para compilar C/C++ upstream. Sin conflicto (ver [ADR 0003](0003-zig-cc-builder.md)).
+- Perfil `release` ya configurado para binarios pequeños (`opt-level=z`, `lto`, `strip`,
+  `panic=abort`).
diff --git a/docs/adr/0002-alpine-first.md b/docs/adr/0002-alpine-first.md
new file mode 100644
index 00000000..bd6d1f79
--- /dev/null
+++ b/docs/adr/0002-alpine-first.md
@@ -0,0 +1,34 @@
+# ADR 0002 — Validar sobre Alpine antes de la distro propia
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+El instinto es construir la distro desde el bootstrap (toolchain, init, userland) y luego poner
+la capa AI-nativa encima. Pero el bootstrap from-scratch es el trabajo más largo y arriesgado
+del proyecto (meses), y **no es donde está la innovación**. La innovación es la capa AI-nativa:
+build determinista + mutable + diario + `.swm`.
+
+## Decisión
+
+Montar y validar toda la capa de `hammer` **sobre Alpine Linux** (Fases 0–6). Sólo después,
+una vez probado el concepto, bajar a la distro propia (track posterior).
+
+## Razones
+
+- Alpine ya es **musl + busybox + FHS mutable + minimalista** — exactamente nuestra filosofía,
+  ya cocida y mantenida.
+- Permite validar el bucle disruptivo (overlay, diario, `.swm`, bus de IA) **en semanas**, no
+  meses.
+- Todo el tooling (Rust) y el lab (`zig cc`) se reusan sin retrabajo cuando bajemos a la distro
+  propia: cambia el *suelo*, no las herramientas.
+
+## Consecuencias
+
+- En la fase Alpine, `/store` y `/var/lib/hammer` viven dentro del rootfs de Alpine; el init es
+  el de Alpine (OpenRC), no el propio. El bus por pipes nativo del init propio es track posterior.
+- No probamos el bootstrap completo en esta fase; `zig cc` cubre la compilación sin necesitar
+  bootstrap (ver [ADR 0003](0003-zig-cc-builder.md)).
+- Riesgo: alguna fricción musl/static en Alpine que no represente la distro propia. Aceptable —
+  Alpine es musl real, la fricción es representativa.
diff --git a/docs/adr/0003-zig-cc-builder.md b/docs/adr/0003-zig-cc-builder.md
new file mode 100644
index 00000000..db0da337
--- /dev/null
+++ b/docs/adr/0003-zig-cc-builder.md
@@ -0,0 +1,36 @@
+# ADR 0003 — `zig cc` como compilador por defecto del laboratorio
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+El lab compila C/C++ upstream de forma hermética hacia un target musl, idealmente estático, y
+debe evitar contaminación del host. La opción clásica es construir un cross-toolchain (Stage 0)
+a mano: largo y frágil.
+
+## Decisión
+
+Usar **`zig cc` como compilador por defecto** del lab, con el compilador **configurable por
+receta** (escotilla a `clang`/`gcc`). Esto es ortogonal al lenguaje del tooling, que es Rust
+([ADR 0001](0001-rust-for-tooling.md)): Rust orquesta, `zig cc` aprieta el tornillo.
+
+## Razones
+
+- **Mata el bootstrap:** un solo binario (~45 MB) provee compilador C/C++ + **musl** + headers,
+  para múltiples arquitecturas. Resuelve gran parte del Stage 0/1.
+- **Hermético por defecto:** trae sus propios headers de libc, no chupa `/usr/include` del
+  host. Justo nuestro requisito de no-contaminación.
+- **Cross-compile trivial:** `-target x86_64-linux-musl`, aarch64, etc. Clave para el track de
+  distro propia y otras arquitecturas.
+- **Determinista:** ayuda directamente al hashing CAS y a la reproducibilidad
+  ([SDD 09](../09-trust-model.md)).
+
+## Consecuencias / riesgos
+
+- `zig cc` es clang por debajo: algunos paquetes con **gcc-ismos** (extensiones GNU, flags
+  específicos) o `configure` de autotools mal detectado **fallarán**. Por eso el compilador es
+  **por receta**, no global: escotilla a `clang`/`gcc` cuando haga falta.
+- No todo upstream compila limpio con clang/musl independientemente del compilador; es fricción
+  inherente a musl/static, no de `zig`.
+- La versión de `zig` forma parte del hash de entrada del build (reproducibilidad).
diff --git a/docs/adr/0004-no-custom-nix.md b/docs/adr/0004-no-custom-nix.md
new file mode 100644
index 00000000..c750c95b
--- /dev/null
+++ b/docs/adr/0004-no-custom-nix.md
@@ -0,0 +1,34 @@
+# ADR 0004 — No escribir nuestro propio Nix
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+Es tentador escribir desde cero un motor completo de grafo de dependencias con caché
+content-addressed, resolución, y aislamiento — "nuestro propio Nix". El concepto de hashing de
+derivaciones es el núcleo de nuestra fábrica.
+
+## Decisión
+
+**No** construir un motor de build genérico tipo Nix desde cero. Implementamos lo **mínimo**
+que necesita `hammer`: un builder con recetas explícitas, sandbox `bubblewrap`, hashing CAS
+BLAKE3 de entradas conocidas, y un DAG simple de dependencias declaradas. Nada de un lenguaje
+funcional, evaluación perezosa, ni resolución general de paquetes.
+
+## Razones
+
+- Un motor de grafo hermético con caché correcta es, por sí solo, un proyecto de **años**.
+  No es donde está el valor de `hammer`.
+- Nuestro valor es el **pegamento AI-nativo** (overlay + diario + `.swm` + bus), no reescribir
+  teoría de build ya resuelta.
+- El alcance mínimo (recetas explícitas + CAS + DAG) cubre las Fases 0–6 sin esa complejidad.
+
+## Consecuencias
+
+- No tendremos resolución automática de dependencias estilo distro completa al principio; las
+  recetas declaran sus `deps` explícitamente. Suficiente para el MVP.
+- Si en el futuro hiciera falta más potencia de grafo, se evaluará **usar Nix como backend de
+  build** (no reescribirlo) y sólo hidratar su salida a FHS. Decisión diferida.
+- Mantiene el código del lab pequeño, auditable y comprensible — coherente con la filosofía de
+  baja entropía.
diff --git a/docs/adr/0005-hardlink-hydration.md b/docs/adr/0005-hardlink-hydration.md
new file mode 100644
index 00000000..90a27cce
--- /dev/null
+++ b/docs/adr/0005-hardlink-hydration.md
@@ -0,0 +1,37 @@
+# ADR 0005 — Hidratación por hardlinks
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+Hay que llevar artefactos del store content-addressed al FHS real. Tres opciones:
+
+1. **Symlinks al store** (estilo Nix): rutas crípticas, `/bin` lleno de enlaces a un almacén
+   oculto. Es justo el "pueblo fantasma" que rechazamos.
+2. **Copia ciega** al FHS: rutas reales, pero se pierde el dedup y la relación con el store
+   (rollback más torpe, más disco).
+3. **Hardlinks** del store al FHS.
+
+## Decisión
+
+**Hidratación por hardlinks** como modo por defecto (con `patchelf` para normalizar el caso
+dinámico antes del enlace).
+
+## Razones
+
+- **Rutas reales:** `/bin/grep` es un archivo de verdad, no un symlink a `/store/...`.
+  Estructura familiar, control total en la terminal.
+- **Dedup:** el hardlink comparte el inode del store; cero copia mientras no se modifique.
+- **Mutabilidad con red de seguridad:** pisar `/bin/grep` en caliente **rompe el hardlink**
+  (copy-on-write manual); el artefacto del store queda intacto como base de rollback.
+- **Rollback simple:** re-hidratar restaura el hardlink original desde el store.
+
+## Consecuencias
+
+- Hardlinks requieren que store y FHS estén en el **mismo filesystem**. En la fase Alpine viven
+  ambos en el rootfs → OK. En la distro propia se tendrá en cuenta al particionar
+  ([SDD 10](../10-roadmap.md)).
+- El caso dinámico necesita `patchelf` (set-interpreter + set-rpath) **antes** del hardlink
+  ([SDD 03](../03-hydration.md) §4).
+- El GC del store debe contar hardlinks/alcanzabilidad para no borrar artefactos vivos.
diff --git a/docs/adr/0006-pinned-commits.md b/docs/adr/0006-pinned-commits.md
new file mode 100644
index 00000000..a8ab3957
--- /dev/null
+++ b/docs/adr/0006-pinned-commits.md
@@ -0,0 +1,38 @@
+# ADR 0006 — Commits fijados, no `HEAD` vivo
+
+- **Estado:** aceptada
+- **Fecha:** 2026-06-06
+
+## Contexto
+
+La idea original habla de "repositorios vivos" apuntando al `HEAD` de los upstreams. Romántico,
+pero `HEAD` se rompe a diario y destruye el determinismo que justifica todo el laboratorio
+funcional. Sin entrada estable no hay hash estable, no hay caché fiable, y no hay `.swm`
+verificable.
+
+## Decisión
+
+El lab compila **siempre contra commits fijados** (un lockfile, `pins.toml`). "Repositorio
+vivo" significa **rastreo automatizado del upstream con snapshots fijados**, no `HEAD` ciego.
+
+## Razones
+
+- **Reproducibilidad:** entrada idéntica ⇒ hash idéntico ⇒ salida idéntica
+  ([SDD 02](../02-build-lab.md), [SDD 09](../09-trust-model.md)).
+- **Avance ordenado del grafo:** al subir un pin, sólo cambian ese nodo y sus dependientes;
+  sabes exactamente qué commit causó qué fallo.
+- **`.swm` verificable:** dos máquinas con el mismo pin+patch producen el mismo binario; eso es
+  lo que permite "verificar, no confiar".
+
+## Mecanismo de "vivo"
+
+- `pins.toml` mapea `nombre → commit` por upstream.
+- `hammer update [<pkg>]` consulta el upstream, propone subir el pin al nuevo commit, y
+  reconstruye sólo lo afectado. El humano (o la IA) decide cuándo avanzar.
+- Análogo al `flake.lock` de Nix, pero imperativo y bajo tu control.
+
+## Consecuencias
+
+- No hay sorpresas por `HEAD` cambiando bajo tus pies.
+- Mantener los pins al día es una acción explícita (deseable: lo controlas tú/la IA).
+- El pin (commit) forma parte del `artifact_hash`; cambiarlo invalida la caché de ese nodo.
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 00000000..2f915aa0
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,6 @@
+[toolchain]
+# Pin a channel for reproducible local builds. Bump deliberately.
+channel = "stable"
+components = ["rustfmt", "clippy"]
+# musl target for static userland binaries (install with: rustup target add x86_64-unknown-linux-musl)
+targets = ["x86_64-unknown-linux-musl"]