Conversation
… loaded-agent metadata now comes from one canonical Rust path instead of being rebuilt by Python, Node, or MCP wrappers. That lives in jacs/src/simple/core.rs and is surfaced through binding-core/src/lib.rs and binding-core/src/simple_wrapper.rs. On top of that, jacspy/python/jacs/client.py now uses native load_with_info, jacspy/python/jacs/simple.py delegates load/quickstart through JacsClient, jacsnpm/client.ts uses native loadWithInfo, jacsnpm/simple.ts adopts client state instead of reparsing config, and jacs-mcp/src/config.rs now loads through the same shared contract instead of manually rewriting config/env state. I also added parity/characterization tests in the Rust, Python, Node, and MCP suites. Verified: cargo test -p jacs-binding-core --test contract --test simple_wrapper cargo test -p jacs-mcp --test config_loading PYTHONPATH=/Users/jonathan.hendler/personal/JACS/jacspy/python uv run pytest jacspy/tests/test_client.py targeted Node loader tests via npx mocha for the touched client/simple quickstart/load cases One broader Node run of test/client.test.js test/simple.test.js still hit an unrelated existing permission failure in a trust-store agreement test writing under ~/Library/Application Support/jacs/...; the load-refactor-specific tests passed.
…nfig_after_cwd_change -- --nocapture cargo test -p jacs-binding-core --test contract --test simple_wrapper cargo build -p jacs-cli cargo test -p jacs-mcp --test config_loading cargo test -p jacs-mcp --test integration mcp_nested_config_allows_state_files_under_loaded_data_root -- --nocapture cargo test -p jacs-mcp --test integration mcp_sign_state_rejects_file_outside_allowed_roots -- --nocapture env PYTHONPATH=/Users/jonathan.hendler/personal/JACS/jacspy/python uv run pytest jacspy/tests/test_client.py npm run build in jacsnpm/ direct Node runtime assertions for quickstart canonical paths and “no config reopen on load”; the targeted mocha invocation was hanging on open handles in this environment, so I used a runtime assertion script instead.
- /Users/jonathan.hendler/personal/JACS/jacs/src/keystore/mod.rs - KeyPaths struct, FsEncryptedStore refactored from unit struct to stateful struct, 8 new tests
- /Users/jonathan.hendler/personal/JACS/jacs/src/crypt/aes_encrypt.rs - resolve_private_key_password() gains explicit_password: Option<&str> parameter, 5 new tests
- /Users/jonathan.hendler/personal/JACS/jacs/src/schema/utils.rs - check_filesystem_schema_access() accepts config: Option<&Config>
- /Users/jonathan.hendler/personal/JACS/jacs/src/agent/mod.rs - Agent struct gains key_paths, password fields plus getters/setters/helpers
- /Users/jonathan.hendler/personal/JACS/jacs/src/crypt/mod.rs - All FsEncryptedStore instantiations use self.build_fs_store()
- /Users/jonathan.hendler/personal/JACS/jacs/src/simple/core.rs - create_with_params removes EnvRestoreGuard, CREATE_MUTEX, all unsafe set_var
- /Users/jonathan.hendler/personal/JACS/jacs/src/agent/loaders.rs - save_private_key uses canonical resolver
- /Users/jonathan.hendler/personal/JACS/jacs/src/config/mod.rs - publish_to_env() deleted
- /Users/jonathan.hendler/personal/JACS/jacs/src/cli_utils/create.rs - publish_to_env() call removed
Binding core:
- /Users/jonathan.hendler/personal/JACS/binding-core/src/lib.rs - ScopedPrivateKeyEnv deleted, private_key_env_lock deleted, with_private_key_password uses Agent.set_password(), standalone verify uses JenvGuard instead of unsafe
EnvGuard
MCP:
- /Users/jonathan.hendler/personal/JACS/jacs-mcp/src/jacs_tools.rs - configured_state_roots() accepts explicit data_directory
Result: Zero unsafe std::env::set_var in library code. Multi-agent-in-one-process is now safe.
… for nonexistent docs FS backend returns StorageError, SQLite returns DocumentError for get/remove on nonexistent documents. The tests asserted discriminant equality which fails. Updated to verify both backends error (the actual contract) and log the variant mismatch for a future error-parity alignment pass.
make_data_directory_path and make_key_directory_path now strip the storage root prefix from absolute directory paths before passing to the storage backend, preventing the root from being prepended twice. Added MultiStorage::root() getter for filesystem_base_dir.
…get_file() LocalFileSystem ObjectPath strips the leading '/' from absolute paths, so list() returns locations like "Users/foo/bar" instead of relative paths. get_file() then treats these as relative and prepends the storage root again. Fix: strip the filesystem_base_dir prefix from list() results so callers get paths relative to the storage root. Also switch test fixture env vars to relative paths since Agent::new() roots storage at CWD.
The schema resolver strips the leading '/' from absolute paths then passes the result to storage as a relative path, causing path doubling. Use a relative path from the crate root instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
keychainfeature stores private key passwords in macOS Keychain or Linux Secret Service (D-Bus). CLIjacs keychain {set,get,delete,status}commands. Config fieldjacs_keychain_backendwithauto/disabledmodes.resolve_private_key_password()function with priority chain: env var → explicit password → OS keychain → error. Removes scatteredget_required_env_varcalls. Agents gainset_password()andload_by_config_file_only()to avoid env var mutation.list()no longer returns root-prefixed paths that breakget_file(). Schema resolution preserves leading/for absolute filesystempaths.
#[serial]annotations replaced with keyed groups (jacs_env,home_env,cwd_env, etc.). CI splits Rust tests into 3 parallel shards. Guardrail script prevents regression. Two pre-existingrace conditions fixed in
simple/mod.rsanddns/bootstrap.rs.Test plan
cargo test -p jacs --features attestation— core tests with keyed serial groupscargo test -p jacs-binding-core --features a2a,attestation— binding contract testscd jacspy && pytest— Python bindings including PQ2025 agreement flowcd jacsnpm && npm test— Node.js bindings./scripts/check-no-bare-serial.sh— no bare#[serial]annotations