@hasna/instructions 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/README.md +149 -8
  2. package/dist/chunks/apply-7svah2qm.js +25 -0
  3. package/dist/chunks/apply-jp13sa1e.js +25 -0
  4. package/dist/chunks/database-wstmr56z.js +23 -0
  5. package/dist/chunks/index-1cnyjnd7.js +623 -0
  6. package/dist/chunks/index-35z65jsa.js +198 -0
  7. package/dist/chunks/index-3djthcm6.js +117 -0
  8. package/dist/chunks/index-4pfq42t5.js +7300 -0
  9. package/dist/chunks/index-5d7zdftc.js +186 -0
  10. package/dist/chunks/index-7m4j8a33.js +12578 -0
  11. package/dist/chunks/index-8rb7ng2y.js +148 -0
  12. package/dist/chunks/index-arrrx0ed.js +344 -0
  13. package/dist/chunks/index-bsan4c16.js +48 -0
  14. package/dist/chunks/index-bzyxvwcd.js +625 -0
  15. package/dist/chunks/index-fpeyzn3n.js +186 -0
  16. package/dist/chunks/index-fwbs6tma.js +534 -0
  17. package/dist/chunks/index-ma2xmp6c.js +14 -0
  18. package/dist/chunks/index-n3fjspr0.js +119 -0
  19. package/dist/chunks/index-nnwp92tk.js +19 -0
  20. package/dist/chunks/index-z3ma4aqk.js +532 -0
  21. package/dist/chunks/legacy-store-migration-z2m5yzyk.js +322 -0
  22. package/dist/chunks/local-5wvv5xv3.js +694 -0
  23. package/dist/chunks/local-zxa5dpf4.js +518 -0
  24. package/dist/chunks/package-manager-guard-x70xrwk2.js +391 -0
  25. package/dist/chunks/redact-hnq4sc4r.js +16 -0
  26. package/dist/chunks/s3-backup-n2z4fwyh.js +240 -0
  27. package/dist/chunks/s3-config-hhght91k.js +14 -0
  28. package/dist/chunks/s3-object-store-90tgbh6k.js +14 -0
  29. package/dist/chunks/sync-2075deve.js +34 -0
  30. package/dist/chunks/sync-r8t7zsp3.js +34 -0
  31. package/dist/chunks/template-fsfxpe4p.js +16 -0
  32. package/dist/chunks/template-wgnzdn7h.js +16 -0
  33. package/dist/cli/index.js +1681 -15643
  34. package/dist/data/config-store.d.ts +2 -1
  35. package/dist/data/config-store.d.ts.map +1 -1
  36. package/dist/db/database.d.ts +3 -5
  37. package/dist/db/database.d.ts.map +1 -1
  38. package/dist/db/local.d.ts +38 -0
  39. package/dist/db/local.d.ts.map +1 -0
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +13809 -12998
  43. package/dist/lib/apply.d.ts +7 -0
  44. package/dist/lib/apply.d.ts.map +1 -1
  45. package/dist/lib/compact-output.d.ts +1 -0
  46. package/dist/lib/compact-output.d.ts.map +1 -1
  47. package/dist/lib/export.d.ts +22 -3
  48. package/dist/lib/export.d.ts.map +1 -1
  49. package/dist/lib/ids.d.ts +4 -0
  50. package/dist/lib/ids.d.ts.map +1 -0
  51. package/dist/lib/import.d.ts +18 -0
  52. package/dist/lib/import.d.ts.map +1 -1
  53. package/dist/lib/instruction-graph.d.ts.map +1 -1
  54. package/dist/lib/legacy-store-migration.d.ts +39 -0
  55. package/dist/lib/legacy-store-migration.d.ts.map +1 -0
  56. package/dist/lib/managed-skill-runtimes.d.ts +1 -0
  57. package/dist/lib/managed-skill-runtimes.d.ts.map +1 -1
  58. package/dist/lib/session-render.d.ts +3 -0
  59. package/dist/lib/session-render.d.ts.map +1 -1
  60. package/dist/lib/sync-dir.d.ts.map +1 -1
  61. package/dist/mcp/index.js +73 -9462
  62. package/dist/sdk/index.d.ts +2 -0
  63. package/dist/sdk/index.d.ts.map +1 -1
  64. package/dist/sdk/index.js +205 -10
  65. package/dist/sdk/resolve.d.ts +1 -1
  66. package/dist/sdk/resolve.d.ts.map +1 -1
  67. package/dist/sdk/v1-client.d.ts +57 -0
  68. package/dist/sdk/v1-client.d.ts.map +1 -0
  69. package/dist/sdk/v1.generated.d.ts +212 -21
  70. package/dist/sdk/v1.generated.d.ts.map +1 -1
  71. package/dist/server/cloud.d.ts.map +1 -1
  72. package/dist/server/index.d.ts +13 -5
  73. package/dist/server/index.d.ts.map +1 -1
  74. package/dist/server/index.js +8337 -7495
  75. package/dist/server/openapi.d.ts +1264 -92
  76. package/dist/server/openapi.d.ts.map +1 -1
  77. package/dist/server/v1.d.ts +25 -1
  78. package/dist/server/v1.d.ts.map +1 -1
  79. package/dist/status.d.ts +12 -2
  80. package/dist/status.d.ts.map +1 -1
  81. package/dist/storage/cloud-store.d.ts +57 -1
  82. package/dist/storage/cloud-store.d.ts.map +1 -1
  83. package/dist/storage/index.d.ts +7 -0
  84. package/dist/storage/index.d.ts.map +1 -0
  85. package/dist/storage/index.js +725 -0
  86. package/dist/storage/s3-backup.d.ts +76 -0
  87. package/dist/storage/s3-backup.d.ts.map +1 -0
  88. package/dist/storage/s3-config.d.ts +46 -0
  89. package/dist/storage/s3-config.d.ts.map +1 -0
  90. package/dist/storage/s3-object-store.d.ts +70 -0
  91. package/dist/storage/s3-object-store.d.ts.map +1 -0
  92. package/dist/types/index.d.ts +65 -3
  93. package/dist/types/index.d.ts.map +1 -1
  94. package/hasna.contract.json +110 -0
  95. package/migrations/0001_instructions.sql +63 -0
  96. package/migrations/0002_api_keys.sql +20 -0
  97. package/migrations/0003_idempotency_receipts.sql +24 -0
  98. package/package.json +29 -14
  99. package/assets/skills/inbox/SKILL.md +0 -86
  100. package/dist/cli/add-duplicate-target.test.d.ts +0 -2
  101. package/dist/cli/add-duplicate-target.test.d.ts.map +0 -1
  102. package/dist/cli/add-reference-update.test.d.ts +0 -2
  103. package/dist/cli/add-reference-update.test.d.ts.map +0 -1
  104. package/dist/cli/apply-unchanged-snapshot-bloat.test.d.ts +0 -2
  105. package/dist/cli/apply-unchanged-snapshot-bloat.test.d.ts.map +0 -1
  106. package/dist/cli/doctor-reference-duplicates.test.d.ts +0 -2
  107. package/dist/cli/doctor-reference-duplicates.test.d.ts.map +0 -1
  108. package/dist/cli/fail-closed-no-env.test.d.ts +0 -2
  109. package/dist/cli/fail-closed-no-env.test.d.ts.map +0 -1
  110. package/dist/cli/output.test.d.ts +0 -2
  111. package/dist/cli/output.test.d.ts.map +0 -1
  112. package/dist/cli/profile-binding.test.d.ts +0 -2
  113. package/dist/cli/profile-binding.test.d.ts.map +0 -1
  114. package/dist/cli/profile-reads.test.d.ts +0 -2
  115. package/dist/cli/profile-reads.test.d.ts.map +0 -1
  116. package/dist/cli/profile-update.test.d.ts +0 -2
  117. package/dist/cli/profile-update.test.d.ts.map +0 -1
  118. package/dist/cli/project-context.test.d.ts +0 -2
  119. package/dist/cli/project-context.test.d.ts.map +0 -1
  120. package/dist/cli/raw-store-root.test.d.ts +0 -2
  121. package/dist/cli/raw-store-root.test.d.ts.map +0 -1
  122. package/dist/cli/session-apply-managed-input-bound.test.d.ts +0 -2
  123. package/dist/cli/session-apply-managed-input-bound.test.d.ts.map +0 -1
  124. package/dist/cli/session.test.d.ts +0 -2
  125. package/dist/cli/session.test.d.ts.map +0 -1
  126. package/dist/cli/station-profile.test.d.ts +0 -2
  127. package/dist/cli/station-profile.test.d.ts.map +0 -1
  128. package/dist/data/config-store.test.d.ts +0 -2
  129. package/dist/data/config-store.test.d.ts.map +0 -1
  130. package/dist/db/configs.test.d.ts +0 -2
  131. package/dist/db/configs.test.d.ts.map +0 -1
  132. package/dist/db/database.test.d.ts +0 -2
  133. package/dist/db/database.test.d.ts.map +0 -1
  134. package/dist/db/machines.test.d.ts +0 -2
  135. package/dist/db/machines.test.d.ts.map +0 -1
  136. package/dist/db/profile-assets.test.d.ts +0 -2
  137. package/dist/db/profile-assets.test.d.ts.map +0 -1
  138. package/dist/db/profile-config-bindings.test.d.ts +0 -2
  139. package/dist/db/profile-config-bindings.test.d.ts.map +0 -1
  140. package/dist/db/profiles.test.d.ts +0 -2
  141. package/dist/db/profiles.test.d.ts.map +0 -1
  142. package/dist/db/snapshots.test.d.ts +0 -2
  143. package/dist/db/snapshots.test.d.ts.map +0 -1
  144. package/dist/lib/app-home.test.d.ts +0 -2
  145. package/dist/lib/app-home.test.d.ts.map +0 -1
  146. package/dist/lib/apply-batch.test.d.ts +0 -2
  147. package/dist/lib/apply-batch.test.d.ts.map +0 -1
  148. package/dist/lib/apply-dry-run-verdict.test.d.ts +0 -2
  149. package/dist/lib/apply-dry-run-verdict.test.d.ts.map +0 -1
  150. package/dist/lib/apply-secret-placeholder-guard.test.d.ts +0 -2
  151. package/dist/lib/apply-secret-placeholder-guard.test.d.ts.map +0 -1
  152. package/dist/lib/apply-text-format-credential-guard.test.d.ts +0 -2
  153. package/dist/lib/apply-text-format-credential-guard.test.d.ts.map +0 -1
  154. package/dist/lib/apply.test.d.ts +0 -2
  155. package/dist/lib/apply.test.d.ts.map +0 -1
  156. package/dist/lib/asset-plan.test.d.ts +0 -2
  157. package/dist/lib/asset-plan.test.d.ts.map +0 -1
  158. package/dist/lib/client-types.test.d.ts +0 -2
  159. package/dist/lib/client-types.test.d.ts.map +0 -1
  160. package/dist/lib/codewith-shared-todos-storage-standard.test.d.ts +0 -2
  161. package/dist/lib/codewith-shared-todos-storage-standard.test.d.ts.map +0 -1
  162. package/dist/lib/compact-output.test.d.ts +0 -2
  163. package/dist/lib/compact-output.test.d.ts.map +0 -1
  164. package/dist/lib/config-target-identity.test.d.ts +0 -2
  165. package/dist/lib/config-target-identity.test.d.ts.map +0 -1
  166. package/dist/lib/cursor-authority.test.d.ts +0 -2
  167. package/dist/lib/cursor-authority.test.d.ts.map +0 -1
  168. package/dist/lib/dangerous-operation-guard-standard.test.d.ts +0 -2
  169. package/dist/lib/dangerous-operation-guard-standard.test.d.ts.map +0 -1
  170. package/dist/lib/diff-redaction.test.d.ts +0 -2
  171. package/dist/lib/diff-redaction.test.d.ts.map +0 -1
  172. package/dist/lib/export-import.test.d.ts +0 -2
  173. package/dist/lib/export-import.test.d.ts.map +0 -1
  174. package/dist/lib/global-agent-rules-render-integration.test.d.ts +0 -2
  175. package/dist/lib/global-agent-rules-render-integration.test.d.ts.map +0 -1
  176. package/dist/lib/global-agent-rules-standard.test.d.ts +0 -2
  177. package/dist/lib/global-agent-rules-standard.test.d.ts.map +0 -1
  178. package/dist/lib/global-agent-rules-stored-content.test.d.ts +0 -2
  179. package/dist/lib/global-agent-rules-stored-content.test.d.ts.map +0 -1
  180. package/dist/lib/global-source-coverage.test.d.ts +0 -2
  181. package/dist/lib/global-source-coverage.test.d.ts.map +0 -1
  182. package/dist/lib/instruction-graph-apply.test.d.ts +0 -2
  183. package/dist/lib/instruction-graph-apply.test.d.ts.map +0 -1
  184. package/dist/lib/instruction-graph.test.d.ts +0 -2
  185. package/dist/lib/instruction-graph.test.d.ts.map +0 -1
  186. package/dist/lib/machine.test.d.ts +0 -2
  187. package/dist/lib/machine.test.d.ts.map +0 -1
  188. package/dist/lib/managed-skill-runtimes.test.d.ts +0 -2
  189. package/dist/lib/managed-skill-runtimes.test.d.ts.map +0 -1
  190. package/dist/lib/package-manager-guard.test.d.ts +0 -2
  191. package/dist/lib/package-manager-guard.test.d.ts.map +0 -1
  192. package/dist/lib/project-context-prepared-file.test.d.ts +0 -2
  193. package/dist/lib/project-context-prepared-file.test.d.ts.map +0 -1
  194. package/dist/lib/project-context.test.d.ts +0 -2
  195. package/dist/lib/project-context.test.d.ts.map +0 -1
  196. package/dist/lib/project-dashboard-standard.test.d.ts +0 -2
  197. package/dist/lib/project-dashboard-standard.test.d.ts.map +0 -1
  198. package/dist/lib/provider-assets-adapters.test.d.ts +0 -2
  199. package/dist/lib/provider-assets-adapters.test.d.ts.map +0 -1
  200. package/dist/lib/provider-context.test.d.ts +0 -2
  201. package/dist/lib/provider-context.test.d.ts.map +0 -1
  202. package/dist/lib/provider-version-adapters.test.d.ts +0 -2
  203. package/dist/lib/provider-version-adapters.test.d.ts.map +0 -1
  204. package/dist/lib/redact.test.d.ts +0 -2
  205. package/dist/lib/redact.test.d.ts.map +0 -1
  206. package/dist/lib/session-apply.test.d.ts +0 -2
  207. package/dist/lib/session-apply.test.d.ts.map +0 -1
  208. package/dist/lib/session-authority.test.d.ts +0 -2
  209. package/dist/lib/session-authority.test.d.ts.map +0 -1
  210. package/dist/lib/session-render-managed-output-bound.test.d.ts +0 -2
  211. package/dist/lib/session-render-managed-output-bound.test.d.ts.map +0 -1
  212. package/dist/lib/session-render-ownership.test.d.ts +0 -2
  213. package/dist/lib/session-render-ownership.test.d.ts.map +0 -1
  214. package/dist/lib/session-render-rule-currency-floor.test.d.ts +0 -2
  215. package/dist/lib/session-render-rule-currency-floor.test.d.ts.map +0 -1
  216. package/dist/lib/session-render-silent-source-drop.test.d.ts +0 -2
  217. package/dist/lib/session-render-silent-source-drop.test.d.ts.map +0 -1
  218. package/dist/lib/session-render-state-hermeticity.test.d.ts +0 -2
  219. package/dist/lib/session-render-state-hermeticity.test.d.ts.map +0 -1
  220. package/dist/lib/session-render-state.test.d.ts +0 -2
  221. package/dist/lib/session-render-state.test.d.ts.map +0 -1
  222. package/dist/lib/session-render.test.d.ts +0 -2
  223. package/dist/lib/session-render.test.d.ts.map +0 -1
  224. package/dist/lib/station-profile.test.d.ts +0 -2
  225. package/dist/lib/station-profile.test.d.ts.map +0 -1
  226. package/dist/lib/sync-dir.test.d.ts +0 -2
  227. package/dist/lib/sync-dir.test.d.ts.map +0 -1
  228. package/dist/lib/sync-dry-run-unchanged.test.d.ts +0 -2
  229. package/dist/lib/sync-dry-run-unchanged.test.d.ts.map +0 -1
  230. package/dist/lib/sync-known.test.d.ts +0 -2
  231. package/dist/lib/sync-known.test.d.ts.map +0 -1
  232. package/dist/lib/sync.test.d.ts +0 -2
  233. package/dist/lib/sync.test.d.ts.map +0 -1
  234. package/dist/lib/template.test.d.ts +0 -2
  235. package/dist/lib/template.test.d.ts.map +0 -1
  236. package/dist/lib/transforms.test.d.ts +0 -2
  237. package/dist/lib/transforms.test.d.ts.map +0 -1
  238. package/dist/lib/transport-resolver.test.d.ts +0 -2
  239. package/dist/lib/transport-resolver.test.d.ts.map +0 -1
  240. package/dist/mcp/create-config-target-guard.test.d.ts +0 -2
  241. package/dist/mcp/create-config-target-guard.test.d.ts.map +0 -1
  242. package/dist/mcp/early-args.test.d.ts +0 -2
  243. package/dist/mcp/early-args.test.d.ts.map +0 -1
  244. package/dist/mcp/http.test.d.ts +0 -2
  245. package/dist/mcp/http.test.d.ts.map +0 -1
  246. package/dist/mcp/mcp.test.d.ts +0 -2
  247. package/dist/mcp/mcp.test.d.ts.map +0 -1
  248. package/dist/sdk/resolve.test.d.ts +0 -2
  249. package/dist/sdk/resolve.test.d.ts.map +0 -1
  250. package/dist/sdk/sdk-bundle-self-contained.test.d.ts +0 -2
  251. package/dist/sdk/sdk-bundle-self-contained.test.d.ts.map +0 -1
  252. package/dist/server/cloud-auth.test.d.ts +0 -2
  253. package/dist/server/cloud-auth.test.d.ts.map +0 -1
  254. package/dist/server/cloud.test.d.ts +0 -2
  255. package/dist/server/cloud.test.d.ts.map +0 -1
  256. package/dist/server/early-args.test.d.ts +0 -2
  257. package/dist/server/early-args.test.d.ts.map +0 -1
  258. package/dist/server/profile-contract.test.d.ts +0 -2
  259. package/dist/server/profile-contract.test.d.ts.map +0 -1
  260. package/dist/status.test.d.ts +0 -2
  261. package/dist/status.test.d.ts.map +0 -1
  262. package/dist/storage/cloud-store.test.d.ts +0 -2
  263. package/dist/storage/cloud-store.test.d.ts.map +0 -1
  264. package/dist/test-support/preload-state-home.d.ts +0 -2
  265. package/dist/test-support/preload-state-home.d.ts.map +0 -1
package/README.md CHANGED
@@ -18,9 +18,15 @@ bun add --global @hasna/instructions
18
18
 
19
19
  ```bash
20
20
  instructions --help
21
- instructions init
21
+
22
+ # Hosted-by-default: resolves the approved key and uses
23
+ # https://api.hasna.com/instructions/v1.
24
+ instructions status
22
25
  instructions list
23
- instructions profile resolve
26
+
27
+ # Explicit on-box SQLite mode; there is never an implicit fallback.
28
+ HASNA_INSTRUCTIONS_LOCAL=1 instructions init
29
+ HASNA_INSTRUCTIONS_LOCAL=1 instructions list
24
30
  ```
25
31
 
26
32
  ## Migrating from `@hasna/configs`
@@ -29,6 +35,19 @@ This package was formerly `@hasna/configs`. The `configs` CLI alias and
29
35
  `configs-mcp` alias remain available for existing integrations; new usage can
30
36
  use the `instructions` names.
31
37
 
38
+ Historical on-box rows can be migrated without overwriting the current store:
39
+
40
+ ```bash
41
+ export HASNA_INSTRUCTIONS_LOCAL=1
42
+ instructions migrate-legacy --confirm-local --json # no-write plan
43
+ instructions migrate-legacy --confirm-local --apply --json # backup + transaction
44
+ ```
45
+
46
+ The source defaults to `~/.hasna/configs/configs.db`; the destination defaults
47
+ to the current `instructions.db`. A non-empty destination is refused unless
48
+ `--merge-preserve-destination` is explicit, and that merge never overwrites an
49
+ existing row.
50
+
32
51
  ## CLI Usage
33
52
 
34
53
  ```bash
@@ -109,8 +128,9 @@ instructions-mcp --http # http://127.0.0.1:8807/mcp
109
128
  MCP_HTTP=1 instructions-mcp
110
129
  ```
111
130
 
112
- Health: `GET http://127.0.0.1:8807/health`. MCP is also mounted on
113
- `instructions-serve` at `/mcp`.
131
+ Health: `GET http://127.0.0.1:8807/health`. The production
132
+ `instructions-serve` process deliberately does **not** mount MCP; local MCP and
133
+ the authenticated `/v1` service remain separate authorities.
114
134
 
115
135
  ## HTTP API server (`instructions-serve`)
116
136
 
@@ -120,14 +140,20 @@ instructions-serve
120
140
 
121
141
  Surfaces:
122
142
 
123
- - `GET /health`, `GET /ready`, `GET /version` → `{ status, version, mode }`
143
+ - `GET /health`, `GET /ready`, `GET /version` → `{ status, version, backend }`
124
144
  - `GET /openapi.json`, `GET /v1/openapi.json` → the OpenAPI 3.1 document the SDK
125
145
  is generated from.
126
146
  - `/v1/*` — versioned cloud API (configs, profiles, snapshots, stats).
127
147
  - No `/api/*` — the former local REST surface is not mounted (the removed
128
148
  bundled dashboard was its only consumer).
129
149
 
130
- ### Server data backend (postgresql)
150
+ ### Server data backend (PostgreSQL, fail closed)
151
+
152
+ `instructions-serve` requires `HASNA_INSTRUCTIONS_DATABASE_URL` (or its documented
153
+ alias) for a usable `/v1` service. Without a DSN, `/health` remains a liveness
154
+ probe but reports `backend: "unconfigured"`; `/ready` returns 503 and `/v1`
155
+ returns a stable unavailable error. It never exposes local SQLite over the
156
+ service boundary.
131
157
 
132
158
  When `HASNA_INSTRUCTIONS_DATABASE_URL` is set the `/v1` API reads/writes the
133
159
  shared Postgres **directly** (no local sync/cache in the service) and every
@@ -150,6 +176,16 @@ they resolve `HASNA_INSTRUCTIONS_API_KEY` (or the Keychain / credentials-file
150
176
  tiers) through the one `@hasna/contracts` client resolver, and the authority
151
177
  defaults to the fleet gateway `https://api.hasna.com/instructions`.
152
178
 
179
+ Collection responses are producer-bounded with `limit`/`cursor` envelopes.
180
+ Current clients follow every page; `view=identity` returns an allowlisted
181
+ metadata-only projection for configs, profiles, and machines, without loading
182
+ instruction content or private profile fields. Retryable create and binding
183
+ writes may send `Idempotency-Key`; PostgreSQL stores the authenticated
184
+ principal, operation, canonical request digest, and first committed response in
185
+ the same transaction as the domain mutation. A same-body retry replays that
186
+ response, while key reuse with different bytes returns
187
+ `409 IDEMPOTENCY_KEY_REUSED`.
188
+
153
189
  ## SDK
154
190
 
155
191
  The importable module ships INSIDE `@hasna/instructions` at the `./sdk` export
@@ -203,7 +239,9 @@ The two transports behind `ConfigStore`:
203
239
  - **local** — on-box SQLite (`LocalConfigStore`), **opt-in only**:
204
240
  `HASNA_INSTRUCTIONS_LOCAL=1`, honoured only when the environment configures
205
241
  no authority and no credential. Every local run says `local mode` once on
206
- stderr.
242
+ stderr. The SQLite half is loaded through a single dynamic import and is
243
+ bundled as a separate chunk, so `dist/cli/index.js` and `dist/mcp/index.js`
244
+ ship with zero `bun:sqlite` references and a hosted run never loads it.
207
245
 
208
246
  Retired locations (`~/.hasna/fleet-env`, `~/.hasna/cloud`, `~/.config/hasna`,
209
247
  `$XDG_CONFIG_HOME`, a `~/.instructions/config.json` key store) are inputs
@@ -213,10 +251,91 @@ transport is decided by what resolves, never by a mode word.
213
251
  Clients never hold a database DSN. The raw Postgres connection is a server-only
214
252
  concern (`instructions-serve`), selected by `HASNA_INSTRUCTIONS_DATABASE_URL`.
215
253
 
254
+
255
+
256
+ ## Domain export and import
257
+
258
+ `instructions export` writes a restorable Instructions domain archive v2. The
259
+ archive contains config content and every retained config snapshot, profiles,
260
+ ordered profile membership and config-binding metadata, profile asset bindings,
261
+ and registered machines. Relationships are recorded by stable config/profile
262
+ slugs and machine hostnames, so import can map them safely onto destination IDs.
263
+
264
+ ```bash
265
+ instructions export --output ./instructions-domain.tar.gz
266
+ instructions import ./instructions-domain.tar.gz # exact recovery into an empty destination
267
+ ```
268
+
269
+ V2 is deliberately a recovery format, not a merge format. Import validates the
270
+ complete archive and requires a destination with zero configs, profiles, and
271
+ machines before the first mutation. `--overwrite` is rejected for v2 before
272
+ destination inspection or mutation. Any validation, mutation, or readback
273
+ failure throws and makes the CLI exit nonzero; discard that attempted
274
+ destination and retry from a newly empty database.
275
+
276
+ The manifest contains deterministic per-collection counts and SHA-256 logical
277
+ hashes for pre/post deployment comparison without placing instruction content
278
+ in logs. Exact deployment integrity includes config `created_at`, `updated_at`,
279
+ and `synced_at`; snapshot `created_at`; profile `created_at` and `updated_at`;
280
+ and machine `created_at` plus the exact `last_applied_at` value. After recovery,
281
+ import reads the complete domain back through `ConfigStore` and verifies every
282
+ field that interface can reproduce: config data and versions, retained snapshot
283
+ contents, profiles, ordered bindings, asset mappings, machines, and whether a
284
+ machine was ever applied.
285
+
286
+ `ConfigStore` cannot assign archived config/profile/snapshot/machine creation or
287
+ update timestamps, nor an exact machine `last_applied_at`; generated destination
288
+ IDs are also intentionally remapped by stable slugs and hostnames. These values
289
+ remain protected in the archive's exact integrity hashes but are not recreated
290
+ by recovery. ConfigStore also has no cross-entity transaction, so an operational
291
+ failure may leave a partial destination; the nonzero result is terminal and that
292
+ destination must not be reused. Legacy v1 config-only archives remain importable,
293
+ including their historical skip/overwrite conflict behavior.
294
+
295
+ API keys and idempotency receipts are intentionally excluded: they are security
296
+ and transport state that must be provisioned independently. Feedback is also
297
+ excluded because it is product telemetry, not part of the Instructions
298
+ configuration domain.
299
+
300
+ ## Native S3 backup storage
301
+
302
+ S3 is an **adjunct immutable backup plane**, never a database selector. SQLite
303
+ remains the explicit local authority and PostgreSQL remains the hosted `/v1`
304
+ authority. Setting S3 variables alone never opens SQLite, never selects HTTP,
305
+ and never changes CRUD routing.
306
+
307
+ ```bash
308
+ export HASNA_INSTRUCTIONS_S3_BUCKET=your-private-bucket
309
+ export HASNA_INSTRUCTIONS_AWS_REGION=us-east-1
310
+ # Optional: HASNA_INSTRUCTIONS_S3_PREFIX (default: instructions/)
311
+ # Optional local/S3-compatible endpoint and explicit static credentials.
312
+
313
+ instructions storage status --json
314
+ instructions export --output ./instructions-backup.tar.gz
315
+ instructions storage backup push ./instructions-backup.tar.gz --id 2026-09-15-pre-deploy --dry-run --json
316
+ instructions storage backup push ./instructions-backup.tar.gz --id 2026-09-15-pre-deploy --json
317
+ instructions storage backup verify 2026-09-15-pre-deploy --json
318
+ instructions storage backup pull 2026-09-15-pre-deploy --output ./restored-instructions.tar.gz --json
319
+ ```
320
+
321
+ Each backup uses traversal-safe deterministic keys, an atomically created
322
+ payload, and an atomically created manifest containing SHA-256, byte size,
323
+ content type, and creation time. Native S3 creation uses `If-None-Match: *`;
324
+ concurrent different-byte writers cannot replace the winner, identical replay
325
+ is idempotent, and an injected store without conditional-create support fails
326
+ closed. Pulls verify the payload before an owner-only local file is written.
327
+ Production backup buckets must enable versioning, encryption, public-access
328
+ blocking, and S3 Object Lock with a default retention period. AWS runtime
329
+ credentials may come from Bun's standard AWS chain (including an ECS task role);
330
+ explicit static credentials are optional and must be a complete pair. Status
331
+ never prints credential values or the bucket name.
332
+
333
+ The public importable surface is available at `@hasna/instructions/storage`.
334
+
216
335
  ## Data Directory
217
336
 
218
337
  Local data (the SQLite store and backups) lives under the configs store home,
219
- resolved through `@hasna/paths`. The legacy `~/.hasna/instructions/` default
338
+ resolved by the in-package resolver. The legacy `~/.hasna/instructions/` default
220
339
  (with the `HASNA_CONFIGS_HOME` exact-app override) stays the effective store
221
340
  home until the store has actually been migrated to the XDG config home
222
341
  (`~/.config/hasna/configs` on Linux; `~/Library/Application
@@ -263,6 +382,28 @@ manifests for drift, refuses unmanaged file conflicts unless `--force` is
263
382
  passed, removes stale managed mirrors only when safe, and writes local snapshots
264
383
  before mutating managed files.
265
384
 
385
+ Grok Build and Devin CLI can render global instructions into an explicitly
386
+ selected native home. Pass Grok's `GROK_HOME` directory or Devin's resolved user
387
+ config directory as `--target-home`; the renderer writes a flattened `AGENTS.md`
388
+ and its ownership manifest there. Devin's target is the `devin` config directory,
389
+ not its parent `XDG_CONFIG_HOME` or its credential-data directory.
390
+
391
+ ```bash
392
+ instructions session plan --tool grok --profile work \
393
+ --target-home "$GROK_HOME" --identity-export ./instructions.json --json
394
+ instructions session apply --tool devin --profile work \
395
+ --target-home /absolute/isolated/config/devin --identity-export ./instructions.json
396
+ ```
397
+
398
+ An explicit `--project-root` keeps the project renderer: Grok writes repository
399
+ `AGENTS.md`; Devin writes `.devin/rules/*.md`. Without either explicit target,
400
+ these providers remain blocked. Compiled native profiles select the
401
+ `native-profile` capability (Grok 1.0.13+, Devin 3000.10.21+); conditional bindings
402
+ require an explicit supported fallback because global `AGENTS.md` is always on.
403
+ The existing conflict, drift, symlink and snapshot checks also apply to native homes.
404
+ See [Devin global rules](https://docs.devin.ai/cli/extensibility/rules) and
405
+ [Grok settings](https://docs.x.ai/build/settings) for native home configuration.
406
+
266
407
  ### Session renderer ownership
267
408
 
268
409
  Anything the session renderer writes is off limits to `instructions apply` and
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import {
3
+ applyConfig,
4
+ applyConfigs,
5
+ applyConfigsWithReport,
6
+ compactPathForConfigHome,
7
+ expandPath,
8
+ getConfigHome,
9
+ normalizeTargetPath,
10
+ previewConfigs
11
+ } from "./index-fwbs6tma.js";
12
+ import"./index-4pfq42t5.js";
13
+ import"./index-35z65jsa.js";
14
+ import"./index-3djthcm6.js";
15
+ import"./index-nnwp92tk.js";
16
+ export {
17
+ previewConfigs,
18
+ normalizeTargetPath,
19
+ getConfigHome,
20
+ expandPath,
21
+ compactPathForConfigHome,
22
+ applyConfigsWithReport,
23
+ applyConfigs,
24
+ applyConfig
25
+ };
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import {
3
+ applyConfig,
4
+ applyConfigs,
5
+ applyConfigsWithReport,
6
+ compactPathForConfigHome,
7
+ expandPath,
8
+ getConfigHome,
9
+ normalizeTargetPath,
10
+ previewConfigs
11
+ } from "./index-z3ma4aqk.js";
12
+ import"./index-7m4j8a33.js";
13
+ import"./index-n3fjspr0.js";
14
+ import"./index-fpeyzn3n.js";
15
+ import"./index-bsan4c16.js";
16
+ export {
17
+ previewConfigs,
18
+ normalizeTargetPath,
19
+ getConfigHome,
20
+ expandPath,
21
+ compactPathForConfigHome,
22
+ applyConfigsWithReport,
23
+ applyConfigs,
24
+ applyConfig
25
+ };
@@ -0,0 +1,23 @@
1
+ // @bun
2
+ import {
3
+ getDatabase,
4
+ insertFeedback,
5
+ resetDatabase,
6
+ resetLocalDatabase
7
+ } from "./index-5d7zdftc.js";
8
+ import {
9
+ now,
10
+ slugify,
11
+ uuid
12
+ } from "./index-ma2xmp6c.js";
13
+ import"./index-fpeyzn3n.js";
14
+ import"./index-bsan4c16.js";
15
+ export {
16
+ uuid,
17
+ slugify,
18
+ resetLocalDatabase,
19
+ resetDatabase,
20
+ now,
21
+ insertFeedback,
22
+ getDatabase
23
+ };