Skip to content

Commit 1b7cc3b

Browse files
committed
lots of fixes for quickstart, proper algo defaults
Implemented all three issues with real tests and no new mocks. P1 (Rust regression after default algorithm switch) load_by_id now loads config from the default config path instead of bare defaults, so legacy RSA fixture flows stay consistent: jacs/src/agent/mod.rs:357 Fixture env helper explicitly sets legacy RSA test context (JACS_USE_SECURITY=false, JACS_AGENT_KEY_ALGORITHM=RSA-PSS): jacs/tests/utils.rs:258 Added assertion that fixture-backed load_by_id remains RSA-PSS: jacs/tests/agent_tests.rs:72 Fixed real flaky pq2025 test behavior by isolating per-test scratch dirs (relative paths) and using real keygen/load flows: jacs/tests/pq2025_tests.rs:18 P2 (Node quickstart contract mismatch) Runtime now gives explicit errors for missing quickstart identity and guards JS no-arg calls cleanly: jacsnpm/simple.ts:164, jacsnpm/client.ts:205 Quickstart factory internals no longer dereference options before validation: jacsnpm/simple.ts:495, jacsnpm/client.ts:300 Types now require name and domain: jacsnpm/simple.d.ts:67, jacsnpm/client.d.ts:64 README examples/docs updated to required quickstart options: jacsnpm/README.md:42, jacsnpm/README.md:48, jacsnpm/README.md:462 Added runtime contract tests for missing quickstart params: jacsnpm/test/client.test.js:99, jacsnpm/test/simple.test.js:157 P3 (MCP agent_info path leakage) Removed local filesystem paths from Node MCP jacs_agent_info output: jacsnpm/mcp.ts:700 Removed local filesystem paths from Python MCP jacs_agent_info output: jacspy/python/jacs/adapters/mcp.py:364 Added/updated tests asserting path fields are not exposed: jacsnpm/test/mcp.test.js:752, jacspy/tests/test_adapters_mcp.py:181 In the docs hat I corrected Node README quickstart password behavior now matches runtime (JACS_SAVE_PASSWORD_FILE=true required to persist generated password): jacsnpm/README.md:48 Shared quickstart snippet now reflects both Python and Node path field names and correct password bootstrap behavior: quickstart-persistent-agent.md:1 Node simple API book page now uses required signature (quickstart(options) / quickstartSync(options)) and corrected password note: nodejs/simple-api.md:61, nodejs/simple-api.md:95, nodejs/simple-api.md:97 Python simple API book page now correctly states quickstart can auto-generate password if env is unset: python/simple-api.md:44 Fixed invalid JS quickstart syntax in streaming guide (quickstart({ ... })): guides/streaming.md:75 CLI quickstart reference examples now include required --name and --domain: reference/cli-commands.md:19, reference/cli-commands.md:32 Quick-start guide password section now clearly distinguishes Rust CLI requirements vs Python/Node auto-generation: getting-started/quick-start.md:9 Main/root README and Python README wording now avoids implying no-arg quickstart: README.md:15, jacspy/README.md:42 In algorithm guide, quickstart-valid algorithm list now excludes deprecated pq-dilithium: advanced/algorithm-guide.md:63
1 parent 85f8405 commit 1b7cc3b

File tree

138 files changed

+2525
-588
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+2525
-588
lines changed

README.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ Cryptographic signatures for AI agent outputs so anyone can verify who said what
1010

1111
Zero-config -- one call creates a persistent agent with keys on disk.
1212

13-
### Password Setup (Required)
13+
### Password Setup
1414

15-
Persistent agents require a private-key password before `quickstart()`.
15+
Persistent agents use encrypted private keys. Rust/CLI flows require an explicit password source before `quickstart(...)`. Python/Node quickstart can auto-generate one, but production deployments should still set it explicitly.
1616

1717
```bash
1818
# Option A (recommended): direct env var
@@ -22,15 +22,16 @@ export JACS_PRIVATE_KEY_PASSWORD='use-a-strong-password'
2222
export JACS_PASSWORD_FILE=/secure/path/jacs-password.txt
2323
```
2424

25-
Set exactly one explicit source. If both are set, CLI fails fast to avoid ambiguity.
26-
For Python/Node library usage, set `JACS_PRIVATE_KEY_PASSWORD` in your process environment.
25+
Set exactly one explicit source for CLI. If both are set, CLI fails fast to avoid ambiguity.
26+
For Python/Node library usage, set `JACS_PRIVATE_KEY_PASSWORD` in your process environment (recommended).
2727

2828
### Python
2929

3030
```python
3131
import jacs.simple as jacs
3232

33-
jacs.quickstart()
33+
info = jacs.quickstart(name="payments-agent", domain="payments.example.com")
34+
print(info.config_path, info.public_key_path, info.private_key_path)
3435
signed = jacs.sign_message({"action": "approve", "amount": 100})
3536
result = jacs.verify(signed.raw)
3637
print(f"Valid: {result.valid}, Signer: {result.signer_id}")
@@ -42,7 +43,11 @@ print(f"Valid: {result.valid}, Signer: {result.signer_id}")
4243
const jacs = require('@hai.ai/jacs/simple');
4344

4445
async function main() {
45-
await jacs.quickstart();
46+
const info = await jacs.quickstart({
47+
name: 'payments-agent',
48+
domain: 'payments.example.com',
49+
});
50+
console.log(info.configPath, info.publicKeyPath, info.privateKeyPath);
4651
const signed = await jacs.signMessage({ action: 'approve', amount: 100 });
4752
const result = await jacs.verify(signed.raw);
4853
console.log(`Valid: ${result.valid}, Signer: ${result.signerId}`);
@@ -60,7 +65,7 @@ cargo install jacs --features cli
6065
# Or download a prebuilt binary from GitHub Releases
6166
# https://github.com/HumanAssisted/JACS/releases
6267

63-
jacs quickstart
68+
jacs quickstart --name payments-agent --domain payments.example.com
6469
jacs document create -f mydata.json
6570

6671
# Install and run the Rust MCP server from the CLI
@@ -154,7 +159,7 @@ JACS provides the missing trust layer: identity (who produced this?), integrity
154159

155160
## Post-Quantum Ready
156161

157-
JACS supports ML-DSA-87 (FIPS-204) post-quantum signatures alongside classical algorithms (Ed25519, ECDSA P-256/P-384, RSA-PSS). The `pq2025` algorithm preset gives you quantum-resistant signing today, with zero code changes from the standard API.
162+
JACS supports ML-DSA-87 (FIPS-204) post-quantum signatures alongside classical algorithms (Ed25519 and RSA-PSS). The `pq2025` algorithm preset is the default across quickstart/create paths.
158163

159164
[Algorithm Selection Guide](https://humanassisted.github.io/JACS/advanced/algorithm-guide.html)
160165

@@ -169,19 +174,30 @@ Built-in trust policies control how your agent handles foreign signatures: `open
169174
```python
170175
from jacs.client import JacsClient
171176

172-
client = JacsClient.quickstart()
177+
client = JacsClient.quickstart(name="a2a-agent", domain="a2a.example.com")
173178
card = client.export_agent_card("http://localhost:8080")
174179
signed = client.sign_artifact({"action": "classify", "input": "hello"}, "task")
175180
```
176181

177182
```javascript
178183
const { JacsClient } = require('@hai.ai/jacs/client');
179184

180-
const client = await JacsClient.quickstart();
185+
const client = await JacsClient.quickstart({
186+
name: 'a2a-agent',
187+
domain: 'a2a.example.com',
188+
});
181189
const card = client.exportAgentCard();
182190
const signed = await client.signArtifact({ action: 'classify', input: 'hello' }, 'task');
183191
```
184192

193+
For trust bootstrap flows, use a signed agent document plus an explicit public key exchange:
194+
195+
```python
196+
agent_json = client.share_agent()
197+
public_key_pem = client.share_public_key()
198+
client.trust_agent_with_key(agent_json, public_key_pem)
199+
```
200+
185201
[A2A Guide](https://humanassisted.github.io/JACS/integrations/a2a.html) | [Python A2A](https://humanassisted.github.io/JACS/python/a2a.html) | [Node.js A2A](https://humanassisted.github.io/JACS/nodejs/a2a.html)
186202

187203
## Cross-Language Compatibility

binding-core/src/lib.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -853,10 +853,10 @@ impl AgentWrapper {
853853
///
854854
/// Replaces the inner agent with a freshly created ephemeral agent that
855855
/// lives entirely in memory. Returns a JSON string with agent info
856-
/// (agent_id, name, version, algorithm).
856+
/// (agent_id, name, version, algorithm). Default algorithm is `pq2025`.
857857
pub fn ephemeral(&self, algorithm: Option<&str>) -> BindingResult<String> {
858858
// Map user-friendly names to internal algorithm strings
859-
let algo = match algorithm.unwrap_or("ed25519") {
859+
let algo = match algorithm.unwrap_or("pq2025") {
860860
"ed25519" => "ring-Ed25519",
861861
"rsa-pss" => "RSA-PSS",
862862
"pq2025" => "pq2025",
@@ -1723,6 +1723,20 @@ pub fn trust_agent(agent_json: &str) -> BindingResult<String> {
17231723
.map_err(|e| BindingCoreError::trust_failed(format!("Failed to trust agent: {}", e)))
17241724
}
17251725

1726+
/// Add an agent to the local trust store using an explicitly provided public key.
1727+
///
1728+
/// This is the recommended first-contact bootstrap for secure trust establishment.
1729+
pub fn trust_agent_with_key(agent_json: &str, public_key_pem: &str) -> BindingResult<String> {
1730+
if public_key_pem.trim().is_empty() {
1731+
return Err(BindingCoreError::invalid_argument(
1732+
"public_key_pem cannot be empty",
1733+
));
1734+
}
1735+
jacs::trust::trust_agent_with_key(agent_json, Some(public_key_pem)).map_err(|e| {
1736+
BindingCoreError::trust_failed(format!("Failed to trust agent with explicit key: {}", e))
1737+
})
1738+
}
1739+
17261740
/// List all trusted agent IDs.
17271741
pub fn list_trusted_agents() -> BindingResult<Vec<String>> {
17281742
jacs::trust::list_trusted_agents().map_err(|e| {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Quickstart + PQ2025 + Framework Exposure: Granular TDD Task List
2+
3+
Scope: implement and verify the five requested changes across Rust core, Python bindings, Node bindings, docs, and tests.
4+
5+
## Workstream A — Quickstart Identity Contract
6+
7+
Goal: `quickstart` requires `name` and `domain`, supports optional `description`, and returns/echoes config and key locations.
8+
9+
### A1. Contract tests first
10+
- [x] Rust: verify `SimpleAgent::quickstart` rejects empty name/domain and returns path-rich `AgentInfo`.
11+
- [x] Python: verify `jacs.quickstart` and `JacsClient.quickstart` reject empty name/domain.
12+
- [x] Node: verify `jacs.quickstart` and `JacsClient.quickstart` reject missing `options.name`/`options.domain`.
13+
14+
### A2. Implement contract in all entry points
15+
- [x] Rust: enforce required `name`/`domain` in `SimpleAgent::quickstart`.
16+
- [x] Python: enforce required `name`/`domain` in simple/client quickstart wrappers.
17+
- [x] Node: enforce required `name`/`domain` in simple/client quickstart wrappers.
18+
19+
### A3. Return operational file locations
20+
- [x] Rust: `AgentInfo` includes `config_path`, key paths, directories.
21+
- [x] Python: expose `config_path`, `public_key_path`, `private_key_path`, directories.
22+
- [x] Node: expose `configPath`, `publicKeyPath`, `privateKeyPath`, directories.
23+
24+
## Workstream B — Default Algorithm Invariant (`pq2025`)
25+
26+
Goal: default algorithm is `pq2025` for creation/quickstart and fallback default paths.
27+
28+
### B1. Config/default tests first
29+
- [x] Rust config tests updated to assert default algorithm `pq2025`.
30+
- [x] Wrapper tests updated where default assumptions previously expected legacy defaults.
31+
32+
### B2. Implement defaults
33+
- [x] Rust config defaults switched to `pq2025`.
34+
- [x] Rust simple creation/quickstart defaults switched to `pq2025`.
35+
- [x] Binding-core creation/quickstart defaults switched to `pq2025`.
36+
- [x] Node wrappers quickstart/default paths switched to `pq2025`.
37+
- [x] Python wrappers quickstart/default paths switched to `pq2025`.
38+
39+
### B3. DRY consolidation
40+
- [x] Normalize wrapper fallback strings to a single consistent default (`pq2025`) per module.
41+
- [ ] Optional follow-up: centralize algorithm default constant across all Node modules.
42+
43+
## Workstream C — Trust Bootstrap Surfaces (MCP + Frameworks)
44+
45+
Goal: expose trust bootstrap primitives for cross-agent handshake flows.
46+
47+
### C1. Tool/API coverage tests first
48+
- [x] Node MCP tests: assert `jacs_share_public_key`, `jacs_share_agent`, `jacs_trust_agent_with_key` tools exist and dispatch correctly.
49+
- [x] Node LangChain tests: assert same trust bootstrap tools exist and dispatch correctly.
50+
- [x] Python MCP adapter tests: assert same trust bootstrap tools are registered.
51+
52+
### C2. Implement and export
53+
- [x] Node MCP adapter exposes share/trust bootstrap tools.
54+
- [x] Node LangChain toolkit exposes share/trust bootstrap tools.
55+
- [x] Python MCP adapter exposes share/trust bootstrap tools.
56+
- [x] Core bindings export `trust_agent_with_key` and wrappers expose client methods.
57+
58+
## Workstream D — Critical Gaps
59+
60+
Goal: remove behavior/docs mismatches that can mislead implementation users.
61+
62+
### D1. A2A well-known defaults
63+
- [x] Node/Python A2A well-known generation fallback `keyAlgorithm` switched to `pq2025`.
64+
- [x] Kept A2A JWS key default (`ring-Ed25519`) in Rust/binding-core for protocol compatibility (A2A JWS key algorithm is distinct from JACS document-signing default).
65+
66+
### D2. Runtime/error guidance
67+
- [x] Node runtime error hints updated to mention `quickstart({ name, domain })`.
68+
- [x] Docs/examples updated away from zero-arg quickstart snippets.
69+
70+
## Workstream E — Documentation and Examples
71+
72+
Goal: align jacsbook/readmes/examples to real code behavior.
73+
74+
### E1. jacsbook core pages
75+
- [x] Front page (`jacsbook/src/README.md`) updated for MCP/A2A/use-case narrative, GO mention, DB integration, DID (no blockchain), encryption/post-quantum emphasis.
76+
- [x] Quick start + simple API pages updated to required quickstart identity and path outputs.
77+
- [x] Reference configuration/migration pages updated for `pq2025` defaults and required quickstart identity.
78+
79+
### E2. jacsbook guide pages
80+
- [x] A2A guides, streaming, integration pages updated for required quickstart identity.
81+
- [x] Multi-agent agreement examples fixed for current quickstart signature.
82+
- [x] Express/Node examples fixed to include `name` and `domain` where quickstart is called directly.
83+
84+
### E3. READMEs and runnable examples
85+
- [x] Root README quickstart and trust bootstrap handshake examples updated.
86+
- [x] `jacspy/README.md` quickstart contract + password behavior corrected.
87+
- [x] Python examples updated to required quickstart identity.
88+
- [x] Node examples updated to required quickstart identity.
89+
90+
## Validation Matrix
91+
92+
- [x] Rust: targeted + feature-gated quickstart/config tests pass.
93+
- [x] Node: build + simple/client/mcp/langchain/a2a/express/koa targeted tests pass.
94+
- [x] Python: focused adapter/a2a/quickstart/client/simple test suites pass.
95+
- [ ] Optional follow-up: run full cross-language fixture matrix in one pass before release cut.
96+
97+
## Notes
98+
99+
- This checklist intentionally keeps one source of truth per behavior and reuses existing adapter/client primitives instead of adding parallel APIs.
100+
- No commits were created in this workstream; changes are review-ready in the working tree.

docs/jacsbook.pdf

28.8 KB
Binary file not shown.

jacs/docs/jacsbook/book/advanced/algorithm-guide.html

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,19 +215,27 @@ <h2 id="configuration"><a class="header" href="#configuration">Configuration</a>
215215
<p>Or via environment variable:</p>
216216
<pre><code class="language-bash">export JACS_AGENT_KEY_ALGORITHM=pq2025
217217
</code></pre>
218-
<p>Valid values: <code>ring-Ed25519</code>, <code>RSA-PSS</code>, <code>pq2025</code>, <code>pq-dilithium</code></p>
219-
<p>In Python and Node.js, pass the algorithm to <code>quickstart()</code>:</p>
218+
<p>Valid values: <code>ring-Ed25519</code>, <code>RSA-PSS</code>, <code>pq2025</code></p>
219+
<p>In Python and Node.js, pass the algorithm to <code>quickstart(...)</code>:</p>
220220
<pre><code class="language-python">from jacs.client import JacsClient
221-
client = JacsClient.quickstart(algorithm="pq2025")
221+
client = JacsClient.quickstart(
222+
name="algo-agent",
223+
domain="algo.example.com",
224+
algorithm="pq2025",
225+
)
222226
</code></pre>
223227
<pre><code class="language-typescript">import { JacsClient } from "@hai.ai/jacs";
224-
const client = await JacsClient.quickstart({ algorithm: "pq2025" });
228+
const client = await JacsClient.quickstart({
229+
name: "algo-agent",
230+
domain: "algo.example.com",
231+
algorithm: "pq2025",
232+
});
225233
</code></pre>
226234
<h2 id="current-limitations"><a class="header" href="#current-limitations">Current Limitations</a></h2>
227235
<ul>
228236
<li>Each agent uses one algorithm, chosen at creation time. You cannot change an agent's algorithm after creation.</li>
229237
<li>Algorithm negotiation between agents is planned but not yet implemented.</li>
230-
<li><code>pq-dilithium</code> is deprecated in favor of <code>pq2025</code> (ML-DSA-87). It remains available for backward compatibility but should not be used for new agents.</li>
238+
<li><code>pq-dilithium</code> is deprecated in favor of <code>pq2025</code> (ML-DSA-87). Use <code>pq2025</code> for new agents and verification hints.</li>
231239
</ul>
232240

233241
</main>

jacs/docs/jacsbook/book/getting-started/decision-tree.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ <h2 id="step-2-pick-your-framework"><a class="header" href="#step-2-pick-your-fr
209209
</tbody></table>
210210
</div>
211211
<h2 id="step-3-your-adoption-path"><a class="header" href="#step-3-your-adoption-path">Step 3: Your Adoption Path</a></h2>
212-
<p><strong>Stage 1 -- Prototyping</strong>: <code>jacs.quickstart()</code>. No config. Explore the API. Keys on disk, auto-managed.</p>
212+
<p><strong>Stage 1 -- Prototyping</strong>: <code>jacs.quickstart(name="my-agent", domain="my-agent.example.com")</code>. No config. Explore the API. Keys on disk, auto-managed.</p>
213213
<p><strong>Stage 2 -- Single-org production</strong>: <code>jacs.load()</code> with persistent agent, strict mode, file-based keys. Add provenance to internal systems.</p>
214214
<p><strong>Stage 3 -- Cross-org production</strong>: DNS trust anchoring, A2A agent cards, agreements with external agents. Operate across trust boundaries.</p>
215215
<p><strong>Stage 4 -- Regulated/enterprise</strong>: Post-quantum algorithms (pq2025/ML-DSA-87), OpenTelemetry observability, audit trails for compliance.</p>

jacs/docs/jacsbook/book/getting-started/deployment.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ <h2 id="docker-example"><a class="header" href="#docker-example">Docker Example<
206206
RUN pip install jacs
207207
COPY . /app
208208
WORKDIR /app
209-
RUN python -c "import jacs.simple as j; j.quickstart()"
209+
RUN python -c "import jacs.simple as j; j.quickstart(name='docker-agent', domain='docker.local')"
210210
CMD ["python", "main.py"]
211211
</code></pre>
212212
<h2 id="lambda-deployment"><a class="header" href="#lambda-deployment">Lambda Deployment</a></h2>

jacs/docs/jacsbook/book/getting-started/multi-agent-agreement.html

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,24 @@ <h2 id="python"><a class="header" href="#python">Python</a></h2>
185185
<pre><code class="language-python">from jacs.client import JacsClient
186186

187187
# Step 1: Create three agents (one per organization)
188-
finance = JacsClient.quickstart("ring-Ed25519", "./finance.config.json")
189-
compliance = JacsClient.quickstart("ring-Ed25519", "./compliance.config.json")
190-
legal = JacsClient.quickstart("ring-Ed25519", "./legal.config.json")
188+
finance = JacsClient.quickstart(
189+
name="finance",
190+
domain="finance.example.com",
191+
algorithm="ring-Ed25519",
192+
config_path="./finance.config.json",
193+
)
194+
compliance = JacsClient.quickstart(
195+
name="compliance",
196+
domain="compliance.example.com",
197+
algorithm="ring-Ed25519",
198+
config_path="./compliance.config.json",
199+
)
200+
legal = JacsClient.quickstart(
201+
name="legal",
202+
domain="legal.example.com",
203+
algorithm="ring-Ed25519",
204+
config_path="./legal.config.json",
205+
)
191206

192207
# Step 2: Finance proposes an agreement with quorum
193208
from datetime import datetime, timedelta, timezone

0 commit comments

Comments
 (0)