Skip to content

Add port discovery for automatic daemon detection#13

Open
Nic-dorman wants to merge 20 commits intomainfrom
feat/port-discovery
Open

Add port discovery for automatic daemon detection#13
Nic-dorman wants to merge 20 commits intomainfrom
feat/port-discovery

Conversation

@Nic-dorman
Copy link
Copy Markdown
Collaborator

Summary

  • antd daemon (Rust): Writes a daemon.port file on startup (atomic write via temp+rename), cleans up on shutdown. Adds --rest-port / --grpc-port CLI flags supporting --rest-port 0 for OS-assigned dynamic ports. Pre-binds both REST and gRPC listeners to capture actual ports before serving.
  • All 15 SDKs: New discover module + auto-discover constructors for REST and gRPC clients. Reads the port file from the platform-specific data directory (%APPDATA%\ant\ on Windows, ~/.local/share/ant/ on Linux, ~/Library/Application Support/ant/ on macOS).
  • Default REST port corrected from 8080 to 8082 across all SDKs, docs, and tooling.
  • ant-dev CLI: status, wallet, and start commands now use port-file discovery.
  • Docs: README, llms.txt, llms-full.txt, skill.md, and MCP README updated with discovery documentation.

Port file format is two lines (REST port, gRPC port). Single-line files are forward-compatible (gRPC falls back to default 50051).

Enables managed mode for consumers like indelible that spawn antd as a child process with a dynamic port.

Test plan

  • cargo check passes for antd (Rust)
  • go test ./... passes for antd-go (8 discovery tests + existing suite)
  • Python discovery tests pass (20 tests via pytest)
  • Rust SDK unit tests pass (5 discovery tests)
  • Manual: start antd, verify daemon.port file written
  • Manual: start antd with --rest-port 0, verify auto-discover connects
  • Manual: stop antd, verify port file cleaned up

🤖 Generated with Claude Code

Nic-dorman and others added 4 commits March 25, 2026 11:09
antd now writes a daemon.port file on startup containing the REST and
gRPC ports, enabling all SDK clients to auto-discover the daemon without
hardcoded URLs. This supports managed mode where antd is spawned with
--rest-port 0 for OS-assigned ports.

Changes:
- antd (Rust): port file lifecycle (atomic write/cleanup), --rest-port
  and --grpc-port CLI flags, pre-bound listeners for both servers
- All 15 SDKs: discover module + auto-discover constructors for REST
  and gRPC clients
- Default REST port corrected from 8080 to 8082 across all SDKs
- ant-dev CLI: status/wallet/start commands use port-file discovery
- Docs: README, llms.txt, llms-full.txt, skill.md updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Windows: remove target before rename (fs::rename fails if target
  exists on Windows, unlike Unix atomic replace)
- Stale port file detection: antd now writes its PID as line 3 of the
  port file. Go SDK checks if the process is still alive before trusting
  the discovered ports (platform-specific: signal 0 on Unix,
  FindProcess on Windows)
- Split Go processAlive into discover_unix.go / discover_windows.go
  with build tags for clean cross-compilation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
antd now writes its PID as line 3 of the port file. All SDKs validate
the PID before trusting discovered ports, preventing connections to
dead daemons after crashes.

Platform-specific approaches per language:
- Go: signal 0 (Unix), FindProcess (Windows) via build tags
- Python/MCP: os.kill(pid, 0) — cross-platform on Python 3
- Rust: kill -0 (Unix), tasklist (Windows) via cfg
- Java/Kotlin: ProcessHandle.of(pid).isPresent() — cross-platform
- C#: Process.GetProcessById — cross-platform on .NET 8+
- TypeScript: process.kill(pid, 0) — cross-platform in Node.js
- C++: kill(pid, 0) (Unix), OpenProcess (Windows) via ifdef
- Ruby: Process.kill(0, pid) — cross-platform
- Elixir: System.cmd("kill", ["-0", pid]) on Unix, trust on Windows
- Swift: kill(pid_t, 0) via C interop
- Dart: kill -0 on Unix, trust on Windows
- Lua: os.execute("kill -0") on Unix, trust on Windows
- PHP: posix_kill or /proc check on Unix, tasklist on Windows
- Zig: /proc check on Linux, trust on other platforms

All backward-compatible with 2-line port files (no PID).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CORS: Restrict allowed origin to http://127.0.0.1:{port} instead of
permissive Any. Prevents cross-origin CSRF from malicious webpages.
Non-browser clients (SDKs, CLI, AI agents) are unaffected as they
don't send Origin headers. Matches approach from ant-client.

Wallet: Add GET /v1/wallet/address and GET /v1/wallet/balance REST
endpoints to antd. Returns 400 if no EVM wallet is configured.

Also adds NotImplemented error variant (HTTP 501 / gRPC UNIMPLEMENTED)
for stubbed endpoints.

SDK bindings added for wallet_address() and wallet_balance() across
all 15 language SDKs + MCP server (2 new MCP tools).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nic-dorman and others added 16 commits March 26, 2026 09:52
Replace direct ant-node protocol handling with ant-core's high-level
Client API. This eliminates ~200 lines of manual chunk orchestration
(quote collection, payment proof building, protocol message encoding)
and unblocks future data/file endpoint implementation.

Changes:
- Cargo.toml: ant-node path dep replaced with ant-core git dep
- state.rs: AppState holds ant_core::data::Client instead of raw
  P2PNode + Wallet
- main.rs: Construct Client::from_node().with_wallet()
- chunks.rs: chunk_put/chunk_get use Client methods directly
- grpc/service.rs: Same refactor for gRPC chunk handlers
- error.rs: AntdError::from_core() replaces From<ProtocolError>
- wallet.rs: Access wallet via client.wallet()

Zero ant_node references remain in antd source code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds optional payment_mode ("auto", "merkle", "single") to all data
and file upload methods across antd and all 15 SDKs.

antd types:
- DataPutRequest and FileUploadRequest now accept payment_mode
- DataPutPublicResponse returns chunks_stored and payment_mode_used
- parse_payment_mode/format_payment_mode helpers added

Data and file endpoints remain stubs (501 Not Implemented) due to an
upstream lifetime issue in ant-core's stream closures that prevents
the Client methods from being called in async axum handlers. The types
and parameter plumbing are in place for when ant-core is fixed.

AppState.client wrapped in Arc<Client> for Send + Sync compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With the upstream HRTB lifetime fix (ant-client#8), ant-core's Client
methods can now be called from async axum handlers via tokio::spawn.

Implemented endpoints:
- POST /v1/data/public — upload with self-encryption + merkle payments
- GET  /v1/data/public/{addr} — download via data map
- POST /v1/data/private — upload, return data map to caller
- GET  /v1/data/private — download using caller-provided data map
- POST /v1/files/upload/public — stream-encrypt file from disk
- POST /v1/files/download/public — download file to disk
- POST /v1/dirs/upload/public — upload directory
- POST /v1/dirs/download/public — download directory

All upload endpoints accept optional payment_mode parameter
("auto"/"merkle"/"single"). Default is "auto" which uses merkle
batch payments for 64+ chunks.

Still stubbed (501): archives, cost estimation, data streaming.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d endpoints

- MCP: store_data and upload_file tools now accept payment_mode parameter
- README: Add Payment Modes section explaining auto/merkle/single
- llms.txt: Document payment_mode on data/file PUT endpoints
- llms-full.txt: Add Payment Modes section with SDK examples
- skill.md: Add merkle guidance to data storage pattern
- antd-go/README.md: Add payment mode configuration examples
- antd-mcp/README.md: Update tool table and add Payment Modes section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
antd:
- Data cost: encrypts data to determine chunks, queries network for
  storage quotes, sums prices (skips already-stored chunks)
- File cost: same approach for files on disk
- Wallet approve: POST /v1/wallet/approve calls approve_token_spend()
  to authorize payment contracts (one-time before storage)
- Added self_encryption dependency for cost estimation chunking

SDK bindings added for wallet_approve() across all 15 languages + MCP.
Documentation updated (llms.txt, llms-full.txt, skill.md, READMEs).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When antd is started without AUTONOMI_WALLET_KEY, write operations
(chunk put, data put, file upload, wallet endpoints) now return
503 Service Unavailable instead of 400 Bad Request or 402 Payment
Required. This correctly signals a server configuration issue rather
than a client error — the request is valid but the server can't
fulfil it without a wallet.

- antd: Added ServiceUnavailable error variant (503 / gRPC UNAVAILABLE)
- All 15 SDKs: Added ServiceUnavailableError exception type, mapped 503
- Docs: Updated error tables in llms.txt, llms-full.txt, skill.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Swift fixes:
- AntdClientProtocol: add paymentMode parameter to 4 upload methods
- AntdClient factory: default port 8080 → 8082
- AntdGrpcClient: add missing walletApprove stub

Kotlin fixes:
- AntdClient factory: default port 8080 → 8082
- AntdGrpcClient: add missing walletApprove stub

Port 8080 → 8082 sweep across all remaining files:
- Factory classes (C# AntdClientFactory, Java AsyncAntdClient)
- READMEs (all 15 SDKs + antd)
- OpenAPI spec, test scripts, examples, quickstart docs
- Architecture docs

Zero 8080 references remain in the repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The FFI was depending on the v1 autonomi crate (from maidsafe/autonomi)
which has a completely different API, payment model, and type system
from the v2 ant-core used by antd and all REST/gRPC SDKs.

Fresh rewrite targeting ant-core:
- client.rs: Client with connect(), connect_local(), connect_with_wallet()
  constructors. chunk_put/get, data_put/get (public+private),
  file_upload/download, wallet_approve — all using ant-core Client.
- wallet.rs: Wallet with from_private_key(), address(), balance methods.
- data.rs: PaymentMode parsing helpers shared with client.
- lib.rs: UniFFI result types and error mapping from ant-core errors.

Removed v1 modules (no equivalent in ant-core yet):
- keys.rs, key_derivation.rs (BLS key operations)
- graph.rs (graph entries not in ant-core)
- files.rs (archive types not in ant-core)
- network.rs, payment.rs (replaced by simpler wallet.rs)

Payment model simplified: v1 required PaymentOption on every write
call. v2 configures wallet at init time, handles payment internally,
and supports payment_mode (auto/merkle/single).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README: Remove outdated prerequisite to clone maidsafe/autonomi repo
  (antd now uses ant-core via git dependency, no sibling clone needed)
- Ruby gemspec: Update author/email from MaidSafe to WithAutonomi

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enables applications like indelible to manage their own wallet keys
without passing private keys to antd. The upload flow is split into
prepare (encrypt + collect quotes) and finalize (submit proofs after
external payment).

antd changes:
- POST /v1/upload/prepare — encrypts file, collects quotes, returns
  PaymentIntent with quote hashes, amounts, contract addresses, RPC URL
- POST /v1/upload/finalize — accepts tx_hash map, builds proofs,
  uploads chunks, returns address
- AppState holds pending uploads in-memory (server-side state since
  PreparedUpload contains non-serializable P2P types)
- main.rs: configure EVM network even without wallet (with_evm_network)
  so prepare works in external-signer-only mode
- Updated ant-core to b9c08d61 (includes PR #10 external signer)

SDK bindings: prepare_upload() and finalize_upload() added to all 15
language SDKs + 2 new MCP tools. Docs updated.

No private key crosses the REST API — the key stays in the external
signer (WalletConnect, HSM, app key store).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
antd README:
- Complete rewrite reflecting current state: ant-core dependency,
  port discovery, external signer endpoints, wallet/EVM config
- Fixed stale references: antctl → ant dev, ANT_PEERS → ANTD_PEERS
- Added all new endpoints: wallet, upload prepare/finalize, cost
- Added --rest-port/--grpc-port flags, external signer mode docs
- Corrected endpoint paths to match actual routes
- Updated project structure (port_file.rs, upload.rs, wallet.rs)
- Marked graph and archive endpoints as stubs

Root README:
- Added ant-node as prerequisite for local testnet

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
antd was passing None for merkle_payments_address to
evmlib::Network::new_custom, which meant merkle batch payments
couldn't work on local testnets. The devnet manifest includes
the merkle contract address but it wasn't being forwarded.

Fixes:
- antd main.rs: read EVM_MERKLE_PAYMENTS_ADDRESS env var, pass to
  Network::new_custom (both wallet and external-signer paths)
- scripts/start-local.sh: extract merkle_payments_address from
  devnet manifest, pass as env var
- scripts/start-local.ps1: same
- ant-dev cmd_start.py: pass all EVM env vars (was only passing
  ANTD_PEERS and AUTONOMI_WALLET_KEY — missing rpc_url, token addr,
  payments addr, and merkle addr)
- antd README: document EVM_MERKLE_PAYMENTS_ADDRESS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The wallet private key was being:
- Written to ~/.ant-dev/state.json in plaintext
- Printed (first 10 chars) to console on startup
- Displayed in full via `ant dev wallet show`

While these are ephemeral Anvil test keys on local devnet, the
pattern is unsafe if someone uses a real key.

Fixes:
- State file: store "wallet_configured": true instead of the key
- Console: show "Wallet: configured" instead of key prefix
- `ant dev wallet show`: queries antd for address/balance via REST
  instead of reading the key from state
- Scripts: same change for start-local.sh and start-local.ps1

The private key remains only in the AUTONOMI_WALLET_KEY env var
passed to the antd process — it never touches disk or console.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
With ant-core PR #15 merged (data_prepare_upload), the external signer
flow now works for both files and raw data.

antd:
- POST /v1/data/prepare: accepts base64 data, encrypts, collects
  quotes, returns PaymentIntent (same response as /v1/upload/prepare)
- Uses same finalize endpoint (POST /v1/upload/finalize)
- Updated ant-core to 7bcb6cbc (includes data_prepare_upload)

SDK bindings: prepare_data_upload() added across all 15 languages +
MCP server. Returns same PrepareUploadResult type — finalize_upload()
works for both file and data uploads unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FFI now exposes the two-phase upload flow for Android/iOS apps
that manage their own wallet keys:

- prepare_data_upload(data) — encrypt + collect quotes, returns
  PaymentEntry list with quote hashes, amounts, addresses
- prepare_file_upload(path) — same for files on disk
- finalize_upload(upload_id, tx_hashes) — build proofs + store chunks

PreparedUpload state held in-process via Mutex<HashMap> since it
contains non-serializable P2P types (same pattern as antd).

New types: PaymentEntry, PrepareUploadResult, FinalizeUploadResult.
Updated ant-core to 7bcb6cbc. Added rand dependency for upload IDs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Graph entries (DAG nodes) are being removed from the initial launch
scope. This removes all graph functionality across the entire SDK:

- antd: REST routes, gRPC service, handler, types, proto file, build.rs
- All 15 SDK clients: REST + gRPC methods, model types
- MCP server: 4 graph tools removed
- Tests: graph test cases removed across Go, Python, Rust, Java, C#,
  Dart, Ruby, Lua, PHP
- Examples: graph example files deleted (Python, TypeScript, Java,
  C#, Dart, Kotlin, Lua)
- Docs: graph removed from llms.txt, llms-full.txt, skill.md,
  architecture.md, all quickstart guides, data primitives table
- Scripts: graph test steps removed from test-api.sh/.ps1
- Proto: graph.proto and generated Go bindings deleted

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant