@aomi-labs/client 0.1.16 → 0.1.17

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.
package/README.md CHANGED
@@ -126,6 +126,7 @@ npx @aomi-labs/client chat "swap 1 ETH" --verbose # stream tool calls + r
126
126
  npx @aomi-labs/client app list # list available apps
127
127
  npx @aomi-labs/client model list # list available models
128
128
  npx @aomi-labs/client model set claude-sonnet-4 # switch the current session model
129
+ npx @aomi-labs/client session new # create a fresh active session
129
130
  npx @aomi-labs/client secret list # list configured secret handles
130
131
  npx @aomi-labs/client --secret ALCHEMY_API_KEY=... # ingest a secret for the active session
131
132
  npx @aomi-labs/client log # show full conversation history
@@ -149,6 +150,31 @@ npx @aomi-labs/client chat "send 0 ETH to myself" \
149
150
  The address is persisted in the state file, so subsequent commands in the same
150
151
  session don't need it again.
151
152
 
153
+ ### Chain selection
154
+
155
+ Use `--chain <id>` for the current command when the task is chain-specific:
156
+
157
+ ```bash
158
+ $ npx @aomi-labs/client chat "swap 1 POL for USDC on Polygon" --chain 137
159
+ ```
160
+
161
+ Use `AOMI_CHAIN_ID` when several consecutive commands should share the same
162
+ chain context.
163
+
164
+ ### Fresh sessions
165
+
166
+ Use `--new-session` when you want a command to start a fresh backend/local
167
+ session instead of reusing the currently active one:
168
+
169
+ ```bash
170
+ $ npx @aomi-labs/client chat "show my balances" --new-session
171
+ $ npx @aomi-labs/client --secret ALCHEMY_API_KEY=... --new-session
172
+ $ npx @aomi-labs/client session new
173
+ ```
174
+
175
+ This is useful when starting a new operator flow or a new external chat thread
176
+ and you do not want stale session state to bleed into the next run.
177
+
152
178
  ### Model selection
153
179
 
154
180
  The CLI can discover and switch backend models for the active session:
package/dist/cli.js CHANGED
@@ -22,7 +22,7 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
22
22
  // package.json
23
23
  var package_default = {
24
24
  name: "@aomi-labs/client",
25
- version: "0.1.16",
25
+ version: "0.1.17",
26
26
  description: "Platform-agnostic TypeScript client for the Aomi backend API",
27
27
  type: "module",
28
28
  main: "./dist/index.cjs",
@@ -139,6 +139,12 @@ function parseSecret(value, secrets) {
139
139
  secrets[value.slice(0, eqIdx)] = value.slice(eqIdx + 1);
140
140
  }
141
141
  }
142
+ function normalizePrivateKey(value) {
143
+ if (value === void 0) return void 0;
144
+ const trimmed = value.trim();
145
+ if (!trimmed) return void 0;
146
+ return trimmed.startsWith("0x") ? trimmed : `0x${trimmed}`;
147
+ }
142
148
  function parseArgs(argv) {
143
149
  const raw = argv.slice(2);
144
150
  const command = raw[0] && !raw[0].startsWith("-") ? raw[0] : void 0;
@@ -200,8 +206,11 @@ function getConfig(parsed) {
200
206
  apiKey: (_e = parsed.flags["api-key"]) != null ? _e : process.env.AOMI_API_KEY,
201
207
  app: (_g = (_f = parsed.flags["app"]) != null ? _f : process.env.AOMI_APP) != null ? _g : "default",
202
208
  model: (_h = parsed.flags["model"]) != null ? _h : process.env.AOMI_MODEL,
209
+ freshSession: parsed.flags["new-session"] === "true",
203
210
  publicKey: (_i = parsed.flags["public-key"]) != null ? _i : process.env.AOMI_PUBLIC_KEY,
204
- privateKey: (_j = parsed.flags["private-key"]) != null ? _j : process.env.PRIVATE_KEY,
211
+ privateKey: normalizePrivateKey(
212
+ (_j = parsed.flags["private-key"]) != null ? _j : process.env.PRIVATE_KEY
213
+ ),
205
214
  chainRpcUrl: (_k = parsed.flags["rpc-url"]) != null ? _k : process.env.CHAIN_RPC_URL,
206
215
  chain: parseChainId((_l = parsed.flags["chain"]) != null ? _l : process.env.AOMI_CHAIN_ID),
207
216
  secrets: parsed.secrets,
@@ -1792,20 +1801,29 @@ function buildCliUserState(publicKey, chainId) {
1792
1801
  }
1793
1802
 
1794
1803
  // src/cli/context.ts
1795
- function getOrCreateSession(runtime) {
1804
+ function buildSessionState(runtime) {
1805
+ const { config } = runtime;
1806
+ return {
1807
+ sessionId: crypto.randomUUID(),
1808
+ baseUrl: config.baseUrl,
1809
+ app: config.app,
1810
+ model: config.model,
1811
+ apiKey: config.apiKey,
1812
+ publicKey: config.publicKey,
1813
+ chainId: config.chain,
1814
+ clientId: crypto.randomUUID()
1815
+ };
1816
+ }
1817
+ function createFreshSessionState(runtime) {
1818
+ const state = buildSessionState(runtime);
1819
+ writeState(state);
1820
+ return state;
1821
+ }
1822
+ function getOrCreateSession(runtime, options = {}) {
1796
1823
  const { config } = runtime;
1797
- let state = readState();
1824
+ let state = options.fresh || config.freshSession ? createFreshSessionState(runtime) : readState();
1798
1825
  if (!state) {
1799
- state = {
1800
- sessionId: crypto.randomUUID(),
1801
- baseUrl: config.baseUrl,
1802
- app: config.app,
1803
- apiKey: config.apiKey,
1804
- publicKey: config.publicKey,
1805
- chainId: config.chain,
1806
- clientId: crypto.randomUUID()
1807
- };
1808
- writeState(state);
1826
+ state = createFreshSessionState(runtime);
1809
1827
  } else {
1810
1828
  let changed = false;
1811
1829
  if (config.baseUrl !== state.baseUrl) {
@@ -1987,7 +2005,9 @@ async function chatCommand(runtime) {
1987
2005
  fatal("Usage: aomi chat <message>");
1988
2006
  }
1989
2007
  const verbose = runtime.parsed.flags["verbose"] === "true" || runtime.parsed.flags["v"] === "true";
1990
- const { session, state } = getOrCreateSession(runtime);
2008
+ const { session, state } = getOrCreateSession(runtime, {
2009
+ fresh: runtime.config.freshSession
2010
+ });
1991
2011
  try {
1992
2012
  await ingestSecretsIfPresent(runtime, state, session.client);
1993
2013
  await applyRequestedModelIfPresent(runtime, session, state);
@@ -2740,7 +2760,9 @@ async function ingestSecretsCommand(runtime) {
2740
2760
  if (secretEntries.length === 0) {
2741
2761
  fatal("Usage: aomi --secret NAME=value [NAME=value ...]");
2742
2762
  }
2743
- const { session, state } = getOrCreateSession(runtime);
2763
+ const { session, state } = getOrCreateSession(runtime, {
2764
+ fresh: runtime.config.freshSession
2765
+ });
2744
2766
  try {
2745
2767
  const handles = await ingestSecretsIfPresent(
2746
2768
  runtime,
@@ -2873,6 +2895,12 @@ async function sessionsCommand(_runtime) {
2873
2895
  async function sessionCommand(runtime) {
2874
2896
  const subcommand = runtime.parsed.positional[0];
2875
2897
  const selector = runtime.parsed.positional[1];
2898
+ if (subcommand === "new") {
2899
+ const state = createFreshSessionState(runtime);
2900
+ console.log(`Active session set to ${state.sessionId} (new).`);
2901
+ printDataFileLocation();
2902
+ return;
2903
+ }
2876
2904
  if (subcommand === "resume") {
2877
2905
  if (!selector) {
2878
2906
  fatal("Usage: aomi session resume <session-id|session-N|N>");
@@ -2908,7 +2936,7 @@ async function sessionCommand(runtime) {
2908
2936
  return;
2909
2937
  }
2910
2938
  fatal(
2911
- "Usage: aomi session list\n aomi session resume <session-id|session-N|N>\n aomi session delete <session-id|session-N|N>"
2939
+ "Usage: aomi session list\n aomi session new\n aomi session resume <session-id|session-N|N>\n aomi session delete <session-id|session-N|N>"
2912
2940
  );
2913
2941
  }
2914
2942
 
@@ -3840,6 +3868,7 @@ Usage:
3840
3868
  aomi model set <rig> Set the active model for the current session
3841
3869
  aomi chain list List supported chains
3842
3870
  aomi session list List local sessions with metadata
3871
+ aomi session new Start a fresh local/backend session and make it active
3843
3872
  aomi session resume <id>
3844
3873
  Resume a local session (session-id or session-N)
3845
3874
  aomi session delete <id>
@@ -3860,6 +3889,8 @@ Options:
3860
3889
  --api-key <key> API key for non-default apps
3861
3890
  --app <name> App (default: "default")
3862
3891
  --model <rig> Set the active model for this session
3892
+ --new-session Create a fresh active session for this command
3893
+ --chain <id> Active chain for chat/session context
3863
3894
  --public-key <addr> Wallet address (so the agent knows your wallet)
3864
3895
  --private-key <key> Hex private key for signing
3865
3896
  --rpc-url <url> RPC URL for transaction submission
@@ -3887,6 +3918,7 @@ Environment (overridden by flags):
3887
3918
  AOMI_API_KEY API key
3888
3919
  AOMI_APP App
3889
3920
  AOMI_MODEL Model rig
3921
+ AOMI_CHAIN_ID Active chain for chat/session context
3890
3922
  AOMI_PUBLIC_KEY Wallet address
3891
3923
  AOMI_AA_PROVIDER AA provider: alchemy | pimlico
3892
3924
  AOMI_AA_MODE AA mode: 4337 | 7702
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aomi-labs/client",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Platform-agnostic TypeScript client for the Aomi backend API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -0,0 +1,46 @@
1
+ # Aomi Skills
2
+
3
+ Agent skills for interacting with the [Aomi](https://aomi.dev) on-chain AI transaction builder.
4
+
5
+ ## Skills
6
+
7
+ | Skill | Description |
8
+ |-------|-------------|
9
+ | [aomi-app-builder](aomi-app-builder/SKILL.md) | Build Aomi apps and plugins from APIs, specs, SDK docs, runtime interfaces, and product requirements |
10
+ | [aomi-transact](aomi-transact/SKILL.md) | Build and execute EVM transactions through a conversational AI agent via the `aomi` CLI |
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npx skills add aomi-labs/skills
16
+ ```
17
+
18
+ Works with Claude Code, Cursor, Gemini CLI, VS Code Copilot, and any [Agent Skills](https://agentskills.io)-compatible tool.
19
+
20
+ ## Prerequisites
21
+
22
+ ```bash
23
+ npm install -g @aomi-labs/client
24
+ ```
25
+
26
+ For transaction signing, also install [viem](https://viem.sh):
27
+
28
+ ```bash
29
+ npm install -g viem
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ Once installed, ask your agent:
35
+
36
+ - "What's the price of ETH?"
37
+ - "Swap 1 ETH for USDC on Uniswap"
38
+ - "Send 0.1 ETH to vitalik.eth"
39
+
40
+ The agent handles the full flow: chat with the backend, review pending transactions, sign and broadcast on-chain.
41
+
42
+ ## Resources
43
+
44
+ - [@aomi-labs/client on npm](https://www.npmjs.com/package/@aomi-labs/client)
45
+ - [Aomi Widget](https://github.com/aomi-labs/aomi-widget)
46
+ - [Agent Skills Spec](https://agentskills.io)
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: aomi-app-builder
3
+ description: >
4
+ Use when the user wants to build, scaffold, or update an Aomi app/plugin from
5
+ API docs, OpenAPI or Swagger specs, SDK docs, repository examples, endpoint
6
+ notes, runtime interfaces, or product requirements. Converts specs into Aomi
7
+ SDK crates with `lib.rs`, `client.rs`, and `tool.rs`, plus tool schemas,
8
+ preambles, host-interop flows, and validation steps. Prefer real product
9
+ integrations over docs-only helpers whenever a callable surface exists.
10
+ compatibility: "Best when a local `aomi-sdk` checkout is available, often at `../aomi-sdk`. Falls back to bundled references when the SDK repo is not present."
11
+ license: MIT
12
+ allowed-tools: Bash
13
+ metadata:
14
+ author: aomi-labs
15
+ version: "0.1"
16
+ ---
17
+
18
+ # Aomi App Builder
19
+
20
+ Use this skill for tasks like:
21
+
22
+ - "Build an Aomi app from this OpenAPI spec."
23
+ - "Turn these REST endpoints into an Aomi plugin."
24
+ - "Scaffold a new Aomi SDK app for this product/API."
25
+ - "Update an existing Aomi app to support these new endpoints."
26
+ - "Turn these builder docs or SDK repos into an Aomi assistant."
27
+
28
+ ## First Read
29
+
30
+ If a local `aomi-sdk` checkout exists, inspect these first:
31
+
32
+ - `sdk/examples/app-template-http/src/lib.rs`
33
+ - `sdk/examples/app-template-http/src/client.rs`
34
+ - `sdk/examples/app-template-http/src/tool.rs`
35
+ - `docs/repo-structure.md`
36
+ - `docs/host-interop.md`
37
+ - 2 or 3 relevant apps under `apps/*/src/{lib,client,tool}.rs`
38
+
39
+ If the supplied docs mostly point to GitHub repositories, SDKs, or examples instead of listing public endpoints:
40
+
41
+ - treat those linked repositories as the real source of truth
42
+ - inspect their README, config examples, example commands, and RPC/API surfaces
43
+ - check whether they expose or produce a runnable service interface such as REST, GraphQL, JSON-RPC, gRPC, webhooks, or another stable client contract
44
+ - prefer building against that executable surface instead of wrapping the docs themselves
45
+ - avoid inventing a public transactional API that the docs do not actually publish
46
+
47
+ If the current repo is `aomi-widget`, also inspect:
48
+
49
+ - `apps/landing/content/examples/*.mdx`
50
+ - `apps/landing/content/guides/build/**/*.mdx`
51
+
52
+ If the SDK repo is not available, read:
53
+
54
+ - [references/aomi-sdk-patterns.md](references/aomi-sdk-patterns.md)
55
+ - [references/spec-to-tools.md](references/spec-to-tools.md)
56
+
57
+ ## Default Workflow
58
+
59
+ 1. Identify the product surface:
60
+ - What external API, SDK, repo, or spec is the source of truth?
61
+ - What concrete callable surface exists: REST, GraphQL, JSON-RPC, gRPC, webhook, CLI contract, or something else?
62
+ - Is there a real target we can point the app at: hosted service, self-hosted node, local example stack, or customer-provided endpoint?
63
+ - Is this read-only, execution-oriented, or mixed?
64
+ - What auth/env vars are required?
65
+ - What user state must come from the host or caller?
66
+ - Is this actually a public end-user API, a standard client interface exposed by a runtime/example app, or only builder-facing documentation?
67
+ 2. Describe the intended user-facing toolset before implementation:
68
+ - list the proposed tools by name
69
+ - say what user intent each tool serves
70
+ - call out which tools are read-only, which prepare actions, and which write or submit
71
+ - mention any expected target URL, runtime, or host dependency
72
+ - if the toolset is uncertain, surface the uncertainty before coding
73
+ - identify the primary user workflow the app should make easy first
74
+ - keep the first pass to the smallest sufficient toolset for that workflow unless the user asked for broader API coverage
75
+ 3. Reduce the spec into semantically meaningful tools.
76
+ 4. Scaffold or update the Aomi app using the standard file split:
77
+ - `lib.rs` for manifest and preamble
78
+ - `client.rs` for HTTP client, auth, models, and normalization
79
+ - `tool.rs` for `DynAomiTool` implementations
80
+ 5. Write the preamble around actual tool behavior, confirmation rules, and any host handoff.
81
+ 6. Validate with the SDK build flow and add focused tests when logic is non-trivial.
82
+
83
+ ## Tool Design Rules
84
+
85
+ - First decide what kind of app this should be:
86
+ - product client
87
+ - execution assistant
88
+ - builder / SDK / runtime assistant
89
+ - Before implementing, state the proposed toolset in concrete user-facing terms. This is part of the design, not optional polish.
90
+ - Prefer the smallest sufficient toolset that makes the primary user workflow work end to end.
91
+ - If there are multiple plausible integration targets, briefly state which one you are choosing and why before coding.
92
+ - Prefer tools that interact with an actual product surface over tools that merely restate documentation.
93
+ - A hosted API is not required. A self-hosted service, local example stack, standard RPC server, or other runnable interface still counts as a real integration target.
94
+ - If the source material is SDK- or architecture-heavy, first ask whether it produces a service that clients call. If yes, build the client for that service.
95
+ - Only fall back to a builder-oriented or docs-oriented tool surface when no stable executable target is available.
96
+ - Do not mirror every endpoint 1:1 unless that is actually the cleanest model-facing API or the user explicitly asked for broad coverage.
97
+ - Prefer 3 to 8 tools with clear user intent boundaries such as `search_*`, `get_*`, `build_*`, `submit_*`, `list_*`, or `resolve_*`.
98
+ - Prefer intent-shaped tool names over raw protocol or transport names when practical.
99
+ - Aggregate noisy upstream endpoints behind a smaller tool surface when the model does not need the raw distinction.
100
+ - Prefer typed arguments over raw JSON string blobs when the primary workflow can be modeled cleanly that way.
101
+ - Separate core tools from escape hatches. A generic fallback tool such as `*_rpc` or `*_raw` is fine, but it should not replace a clean core workflow.
102
+ - Keep args typed and documented with `JsonSchema`. Field doc comments are model-facing and matter.
103
+ - Return stable JSON with predictable keys. Normalize upstream naming, paging, and inconsistent shapes inside `client.rs` or helper functions.
104
+ - Convert upstream errors into short actionable messages. Do not leak raw HTML, secrets, or giant payload dumps.
105
+
106
+ ## File Responsibilities
107
+
108
+ ### `lib.rs`
109
+
110
+ - Keep it easy to scan.
111
+ - Define `PREAMBLE` or a small `build_preamble()` hook.
112
+ - Register tools with `dyn_aomi_app!`.
113
+ - Only keep manifest-level wiring here.
114
+
115
+ ### `client.rs`
116
+
117
+ - Own the app struct, HTTP client, auth headers, env vars, typed models, and response normalization.
118
+ - Prefer `reqwest::blocking::Client` with explicit timeouts for sync tools, matching the current SDK examples.
119
+ - Keep third-party API quirks here instead of spreading them across tool implementations.
120
+
121
+ ### `tool.rs`
122
+
123
+ - Implement `DynAomiTool`.
124
+ - Use descriptions that tell the model when to call the tool, not just what endpoint it wraps.
125
+ - Map normalized client results into concise JSON results.
126
+ - Use `DynToolCallCtx` when host state such as connected wallet, session state, or caller attributes is needed.
127
+
128
+ ## Preamble Rules
129
+
130
+ Write the preamble from the app's real contract:
131
+
132
+ - Define role, capabilities, workflow, and guardrails.
133
+ - Mention tool order for multi-step flows.
134
+ - State explicit confirmation requirements before write actions.
135
+ - If dates matter, include the current date or instruct the app to use exact dates.
136
+ - If the app relies on host wallet/signing tools, say that clearly and do not imply hidden infrastructure.
137
+
138
+ For deeper patterns and examples, read [references/aomi-sdk-patterns.md](references/aomi-sdk-patterns.md).
139
+
140
+ ## Host Interop And Execution
141
+
142
+ For execution-oriented apps:
143
+
144
+ - Follow the public host conventions from `docs/host-interop.md`.
145
+ - Do not invent private namespaces or internal fallback behavior.
146
+ - When the next step belongs to the host wallet or signer, return machine-readable `SYSTEM_NEXT_ACTION` guidance.
147
+ - Preserve exact transaction or signature args when a downstream host tool must execute them.
148
+ - Do not claim a write succeeded until the upstream API submit step has actually completed.
149
+
150
+ ## Validation
151
+
152
+ When working inside `aomi-sdk`:
153
+
154
+ - Scaffold with `cargo run -p xtask -- new-app <name>` if starting from scratch, or copy `sdk/examples/app-template-http`.
155
+ - Build the plugin with `cargo run -p xtask -- build-aomi --app <name>`.
156
+ - If `build-aomi` reports zero built plugins for a brand new app, check whether the new `apps/<name>/Cargo.toml` is still untracked. The current xtask prefers `git ls-files` discovery for app manifests.
157
+ - For a direct compile signal on an untracked app, use `cargo build --manifest-path apps/<name>/Cargo.toml`.
158
+ - If the app has meaningful branching or normalization logic, add unit tests with `aomi_sdk::testing::{TestCtxBuilder, run_tool, run_async_tool}`.
159
+ - If a real target is available, validate the app with a short ladder:
160
+ - compile/build
161
+ - connectivity check
162
+ - one representative read flow
163
+ - one representative write or submit flow when applicable
164
+ - post-write verification such as status, receipt, or refreshed state
165
+ - Prefer proving one end-to-end user scenario over checking many disconnected endpoints.
166
+
167
+ When the task also touches docs or demos in `aomi-widget`, update the relevant examples or guides to match the new app behavior.
168
+
169
+ ## Output Expectations
170
+
171
+ Aim to leave behind:
172
+
173
+ - a coherent Aomi app crate or patch
174
+ - typed tool args and strong descriptions
175
+ - a preamble that explains the tool contract and rules
176
+ - stable JSON outputs for the host/model
177
+ - an app that can point at a real product surface when one exists
178
+ - a short validation pass or a clear note about what could not be verified
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Aomi App Builder"
3
+ short_description: "Build Aomi apps from APIs and specs"
4
+ default_prompt: "Use $aomi-app-builder to turn this API, OpenAPI spec, or product brief into an Aomi SDK app/plugin with a clean tool surface, preamble, and validation plan."
@@ -0,0 +1,191 @@
1
+ # Aomi SDK Patterns
2
+
3
+ These patterns come from the SDK example and the inspected public apps in `aomi-sdk`.
4
+
5
+ ## Canonical Layout
6
+
7
+ Use this split unless there is a strong reason not to:
8
+
9
+ ```text
10
+ apps/my-app/
11
+ ├─ Cargo.toml
12
+ └─ src/
13
+ ├─ lib.rs
14
+ ├─ client.rs
15
+ └─ tool.rs
16
+ ```
17
+
18
+ - `lib.rs`: manifest, preamble, `dyn_aomi_app!`
19
+ - `client.rs`: app struct, HTTP client, auth, models, helpers
20
+ - `tool.rs`: `DynAomiTool` impls and user-facing tool surface
21
+
22
+ ## Minimal Manifest Shape
23
+
24
+ ```rust
25
+ use aomi_sdk::*;
26
+
27
+ mod client;
28
+ mod tool;
29
+
30
+ const PREAMBLE: &str = r#"## Role
31
+ You are ...
32
+ "#;
33
+
34
+ dyn_aomi_app!(
35
+ app = client::MyApp,
36
+ name = "my-app",
37
+ version = "0.1.0",
38
+ preamble = PREAMBLE,
39
+ tools = [
40
+ client::SearchThing,
41
+ client::GetThing,
42
+ ]
43
+ );
44
+ ```
45
+
46
+ Keep `lib.rs` small. The manifest should be easy to audit at a glance.
47
+
48
+ ## What The Real Apps Show
49
+
50
+ ### `sdk/examples/app-template-http`
51
+
52
+ Use as the default baseline for read-only HTTP APIs.
53
+
54
+ - Simple `reqwest::blocking` client
55
+ - Clean typed args
56
+ - Small tool surface
57
+ - Straightforward JSON normalization
58
+
59
+ ### `apps/x`
60
+
61
+ Use this pattern when the upstream API:
62
+
63
+ - needs an env-backed API key
64
+ - has a wrapper response envelope
65
+ - benefits from normalized data models and formatting helpers
66
+
67
+ Notable conventions:
68
+
69
+ - auth env vars live in `client.rs`
70
+ - logical API failures are normalized before reaching tools
71
+ - tools return concise, model-friendly JSON
72
+
73
+ ### `apps/polymarket`
74
+
75
+ Use this pattern when the app needs:
76
+
77
+ - multiple upstream API surfaces
78
+ - dynamic preamble context such as exact current date
79
+ - intent resolution before execution
80
+ - multi-step flows with explicit user confirmation
81
+
82
+ Notable conventions:
83
+
84
+ - preamble explains exact flow order
85
+ - tool surface separates search, details, intent resolution, preview, and submit
86
+ - results include next-step hints without hiding uncertainty
87
+
88
+ ### `apps/khalani`
89
+
90
+ Use this pattern when execution must hand off to host wallet tools.
91
+
92
+ Notable conventions:
93
+
94
+ - app tools never send the wallet request directly
95
+ - build tools return `SYSTEM_NEXT_ACTION`
96
+ - preamble tells the model to preserve exact host args and continue after wallet callbacks
97
+
98
+ ### Executable product integrations
99
+
100
+ When the source material is mostly SDK docs, example repos, runtime notes, or architecture docs, first check whether it exposes or produces a client-facing interface such as:
101
+
102
+ - REST or GraphQL
103
+ - JSON-RPC
104
+ - gRPC
105
+ - webhooks
106
+ - a stable CLI request/response contract
107
+ - a local example service or reference node
108
+
109
+ If such a surface exists:
110
+
111
+ - build the app against that executable interface
112
+ - treat the SDK, example repo, and docs as implementation references
113
+ - expose user-useful operations against the real service, not just summaries of the docs
114
+ - validate with at least one real call when possible
115
+
116
+ ### Builder-oriented fallbacks
117
+
118
+ Use a builder-oriented shape only when the source material is mostly:
119
+
120
+ - SDK documentation
121
+ - example repositories
122
+ - architecture notes
123
+ - runtime / RPC references
124
+ - config files and quickstarts
125
+
126
+ In that case:
127
+
128
+ - do not pretend there is a public swap, quote, or portfolio API unless the source really documents one
129
+ - do not hide the absence of a real integration target
130
+ - prefer tools such as `list_*_resources`, `get_*_overview`, `get_*_quickstart`, `get_*_rpc_surface`, or `get_*_network_defaults`
131
+ - make the preamble explicit that the app is a builder assistant, not an end-user trading agent
132
+ - say clearly what would be needed to upgrade the app into a real client later, such as a base URL, running example service, or customer endpoint
133
+
134
+ ## Tool Authoring Checklist
135
+
136
+ Every tool should answer these:
137
+
138
+ - What user intent does it serve?
139
+ - What exact name should the model call?
140
+ - What fields does the model need to provide?
141
+ - What result shape will be easiest for the model to reason over?
142
+ - If the upstream API is inconsistent, where will normalization happen?
143
+
144
+ Prefer names like:
145
+
146
+ - `search_*`
147
+ - `get_*`
148
+ - `list_*`
149
+ - `resolve_*`
150
+ - `build_*`
151
+ - `submit_*`
152
+
153
+ ## Client Conventions
154
+
155
+ Keep these in `client.rs` whenever possible:
156
+
157
+ - base URLs
158
+ - auth headers
159
+ - shared request helpers
160
+ - response envelopes
161
+ - normalization helpers
162
+ - typed upstream models
163
+
164
+ Prefer short actionable errors such as:
165
+
166
+ - `X_API_KEY environment variable not set`
167
+ - `Gamma API error 404: ...`
168
+ - `Failed to parse markets: ...`
169
+
170
+ ## Validation Commands
171
+
172
+ Inside `aomi-sdk`, the repo documents these as the standard loop:
173
+
174
+ ```bash
175
+ cargo run -p xtask -- new-app my-app
176
+ cargo run -p xtask -- build-aomi --app my-app
177
+ ```
178
+
179
+ One caveat from practice:
180
+
181
+ - `xtask build-aomi` currently prefers tracked `apps/*/Cargo.toml` files via `git ls-files`
182
+ - a brand new untracked app can therefore compile fine but still be skipped by `build-aomi`
183
+ - use `cargo build --manifest-path apps/my-app/Cargo.toml` for an immediate compile check before the new app is tracked
184
+
185
+ For focused logic tests, use the SDK test helpers:
186
+
187
+ ```rust
188
+ use aomi_sdk::testing::{TestCtxBuilder, run_tool};
189
+ ```
190
+
191
+ Use `run_async_tool` only when the tool is actually async.
@@ -0,0 +1,149 @@
1
+ # Spec To Tools
2
+
3
+ Use this when the input is an OpenAPI document, Swagger spec, Postman collection, endpoint list, or product brief.
4
+
5
+ It also applies when the "spec" is really one of these:
6
+
7
+ - SDK docs that link out to source repos
8
+ - runtime / RPC documentation
9
+ - example applications
10
+ - architecture notes with concrete commands, configs, and method names
11
+
12
+ ## Extract First
13
+
14
+ Before writing code, pull out:
15
+
16
+ - base URL and authentication scheme
17
+ - the actual integration target the finished app should call
18
+ - main entities and identifiers
19
+ - read operations vs write operations
20
+ - pagination, filters, and search parameters
21
+ - user-specific inputs the host must provide
22
+ - confirmation or safety requirements
23
+ - rate limits, async jobs, and polling behavior
24
+ - common error shapes
25
+ - whether the docs actually publish an end-user API or mainly document a builder workflow
26
+
27
+ If a detail is missing, do not invent it. Leave a TODO or ask for the smallest missing piece.
28
+
29
+ ## Find The Real Integration Target
30
+
31
+ Prefer the nearest executable product surface over explanatory documentation.
32
+
33
+ Ask these questions early:
34
+
35
+ - What will the finished app actually call?
36
+ - Is there a concrete service contract such as REST, GraphQL, JSON-RPC, gRPC, webhook delivery, or a stable CLI protocol?
37
+ - Is the target hosted, self-hosted, customer-provided, or only available through a local example stack?
38
+ - If the source is an SDK or example project, does it expose a service that clients use after the builder sets it up?
39
+
40
+ Useful rule of thumb:
41
+
42
+ - If users can point the app at a running thing, build the client for that thing.
43
+ - If no running thing exists yet, only then consider a builder or reference assistant.
44
+
45
+ ## Decide The App Type Early
46
+
47
+ Choose one of these before naming tools:
48
+
49
+ - **Product client**: the source exposes a real callable product surface, even if it is self-hosted or example-backed.
50
+ - **Execution assistant**: the docs expose quote/build/submit flows and host or wallet handoff matters.
51
+ - **Builder assistant**: the docs mostly explain how to build on top of a network, SDK, or runtime.
52
+
53
+ Builder assistants are valid outcomes, but they are the fallback, not the default. If the docs mostly point to SDK repos and example stacks, first check whether those repos produce a runnable interface that the app can call.
54
+
55
+ ## Map Endpoints To Model-Facing Tools
56
+
57
+ Do not default to one tool per endpoint. Instead, group endpoints by user intent.
58
+
59
+ Before implementation, write down the proposed toolset explicitly:
60
+
61
+ - tool name
62
+ - what the user would ask for that should trigger it
63
+ - key inputs
64
+ - key outputs
65
+ - whether it reads, prepares, or writes
66
+ - whether it depends on a live target, wallet, signer, or host callback
67
+
68
+ Treat this as a required checkpoint. If the proposed toolset is weak, too docs-oriented, too endpoint-shaped, or not clearly tied to user intent, revise it before writing code.
69
+
70
+ When choosing the first implementation:
71
+
72
+ - optimize for the primary user workflow first
73
+ - keep the toolset as small as possible while still making that workflow work end to end
74
+ - prefer app-specific high-value actions over broad protocol coverage when the source makes the important workflow obvious
75
+ - avoid schema or discovery tools unless they are needed to support the chosen workflow
76
+ - only mirror the wider API surface if the user asked for broad coverage
77
+
78
+ Good mappings:
79
+
80
+ - several lookup endpoints -> `search_*` or `get_*`
81
+ - multiple list and detail calls -> `resolve_*` then `get_*`
82
+ - quote + build + submit endpoints -> `get_*_quote`, `build_*`, `submit_*`
83
+ - create side effects -> preview/build first, then explicit submit after confirmation
84
+ - standard runtime interfaces -> wrap the standard methods first, then add extension hooks or custom methods
85
+ - SDK + example repo + config + RPC docs -> `list_*_resources`, `get_*_overview`, `get_*_quickstart`, `get_*_rpc_surface`, `get_*_defaults`
86
+ - example-backed transactional app -> one health/connectivity tool, a few read tools for key state, one write tool for the main action, and one verification tool for the outcome
87
+
88
+ Less useful mappings:
89
+
90
+ - raw REST verbs as tool names
91
+ - exposing every transport detail directly to the model
92
+ - returning unnormalized upstream payloads when only 20 percent of the fields matter
93
+ - choosing a docs-summary tool surface when a real client could be built instead
94
+ - inventing public user actions that are not actually documented by the source
95
+ - building a large first-pass toolset before proving the primary user workflow
96
+
97
+ ## Preamble Rubric
98
+
99
+ A strong preamble usually includes:
100
+
101
+ - `## Role`
102
+ - `## Capabilities`
103
+ - `## Workflow`
104
+ - `## Rules`
105
+
106
+ For execution apps, spell out:
107
+
108
+ - when confirmation is required
109
+ - which tool comes first
110
+ - which tool hands off to the wallet or host
111
+ - what must be preserved exactly between steps
112
+
113
+ ## Output Shape Rubric
114
+
115
+ Return the minimum stable JSON the model needs for the next step.
116
+
117
+ Good result shapes often include:
118
+
119
+ - a top-level echo of the key input
120
+ - normalized identifiers
121
+ - concise summaries
122
+ - arrays of candidate objects
123
+ - `requires_selection`, `selection_reason`, or `next_step_hint` when ambiguity remains
124
+ - `SYSTEM_NEXT_ACTION` when the host must take over
125
+
126
+ Avoid:
127
+
128
+ - leaking auth credentials
129
+ - giant raw payloads
130
+ - mixed naming conventions from multiple upstream APIs
131
+ - claiming success before the final submit step succeeds
132
+
133
+ ## Suggested Build Loop
134
+
135
+ 1. Read the spec and summarize the app contract.
136
+ 2. Identify the concrete service or runtime target.
137
+ 3. Propose the tool surface in concrete user-facing terms.
138
+ 4. Scaffold or patch `lib.rs`, `client.rs`, and `tool.rs`.
139
+ 5. Normalize auth, models, and errors in `client.rs`.
140
+ 6. Implement small, strongly typed tools.
141
+ 7. Build and test.
142
+ 8. If the target is available, verify a short end-to-end scenario:
143
+ - connectivity
144
+ - key read
145
+ - key write when applicable
146
+ - post-write verification
147
+ 9. Update docs or examples if the repo includes them.
148
+
149
+ If the app is brand new in `aomi-sdk`, remember that `cargo run -p xtask -- build-aomi --app <name>` may skip an untracked app. A direct `cargo build --manifest-path apps/<name>/Cargo.toml` is the fastest compile check until the manifest is tracked.
@@ -36,6 +36,7 @@ backend. Local session data lives under `AOMI_STATE_DIR` or `~/.aomi`.
36
36
  - If the user provides a private key or API key, do not repeat it back unless they explicitly ask for that exact value to be reformatted.
37
37
  - Prefer `aomi --secret NAME=value ...` over stuffing provider API keys into normal chat text.
38
38
  - Do not sign anything unless the CLI has actually queued a wallet request and you can identify its `tx-N` ID.
39
+ - When starting work from a new Codex or assistant chat thread, default the first Aomi command to `--new-session` unless the user explicitly wants to continue an existing session.
39
40
  - If `PRIVATE_KEY` is set in the environment, do not also pass `--private-key` unless you intentionally want to override the environment value.
40
41
  - `--public-key` must match the address derived from the signing key. If they differ, `aomi sign` will update the session to the signer address.
41
42
  - Private keys must start with `0x`. Add the prefix if missing.
@@ -73,7 +74,7 @@ tx-N`, there is nothing to sign yet.
73
74
  Use these when the user does not need signing:
74
75
 
75
76
  ```bash
76
- aomi chat "<message>"
77
+ aomi chat "<message>" --new-session
77
78
  aomi chat "<message>" --verbose
78
79
  aomi tx
79
80
  aomi log
@@ -92,8 +93,10 @@ aomi session resume <id>
92
93
  Notes:
93
94
 
94
95
  - Quote the chat message.
96
+ - On the first command in a new Codex or assistant thread, prefer `--new-session` so old local/backend state does not bleed into the new task.
95
97
  - Use `--verbose` when debugging tool calls or streaming behavior.
96
98
  - Pass `--public-key` on the first wallet-aware chat if the backend needs the user's address.
99
+ - For chain-specific requests, prefer `--chain <id>` on the command itself. Use `AOMI_CHAIN_ID=<id>` only when multiple consecutive commands should stay on the same chain.
97
100
  - Use `aomi secret list` to inspect configured secret handles for the active session.
98
101
  - `aomi close` wipes the active local session pointer and starts a fresh thread next time.
99
102
 
@@ -103,8 +106,8 @@ Use this when the backend or selected app needs API keys, provider tokens, or
103
106
  other named secrets for the current session:
104
107
 
105
108
  ```bash
106
- aomi --secret ALCHEMY_API_KEY=sk_live_123
107
- aomi --secret ALCHEMY_API_KEY=sk_live_123 chat "simulate a swap on Base"
109
+ aomi --secret ALCHEMY_API_KEY=sk_live_123 --new-session
110
+ aomi --secret ALCHEMY_API_KEY=sk_live_123 chat "simulate a swap on Base" --new-session
108
111
  aomi secret list
109
112
  aomi secret clear
110
113
  ```
@@ -123,7 +126,7 @@ Use the first chat turn to give the agent the task and, if relevant, the wallet
123
126
  address and chain:
124
127
 
125
128
  ```bash
126
- aomi chat "swap 1 ETH for USDC" --public-key 0xYourAddress --chain 1
129
+ aomi chat "swap 1 ETH for USDC" --new-session --public-key 0xYourAddress --chain 1
127
130
  ```
128
131
 
129
132
  If the user wants a different backend app or chain, pass them explicitly on the
@@ -210,7 +213,7 @@ aomi close
210
213
  ### Chat
211
214
 
212
215
  ```bash
213
- aomi chat "<message>"
216
+ aomi chat "<message>" --new-session
214
217
  aomi chat "<message>" --verbose
215
218
  aomi chat "<message>" --model <rig>
216
219
  aomi chat "<message>" --public-key 0xYourAddress --chain 1
@@ -218,9 +221,11 @@ aomi chat "<message>" --app khalani --chain 137
218
221
  ```
219
222
 
220
223
  - Quote the message.
224
+ - On the first command in a new Codex or assistant thread, prefer `--new-session`.
221
225
  - Use `--verbose` to stream tool calls and agent output.
222
226
  - Use `--public-key` on the first wallet-aware message.
223
227
  - Use `--app`, `--model`, and `--chain` to change the active context for the next request.
228
+ - Prefer `--chain <id>` for one-off chain-specific requests. Use `AOMI_CHAIN_ID=<id>` when several consecutive commands should share the same chain context.
224
229
 
225
230
  ### Transaction Inspection
226
231
 
@@ -265,6 +270,7 @@ aomi chain list
265
270
 
266
271
  ```bash
267
272
  aomi session list
273
+ aomi session new
268
274
  aomi session resume <id>
269
275
  aomi session delete <id>
270
276
  aomi close