kira-wallet 0.1.5 → 0.1.7
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 +14 -4
- package/THIRD_PARTY_NOTICES.md +6 -0
- package/docs/AGENT_TOOLS.md +13 -0
- package/docs/ALCHEMY_SETUP.md +95 -0
- package/docs/CLI.md +14 -5
- package/docs/FREE_RPC.md +112 -0
- package/docs/JOB_CONTRACT.md +24 -0
- package/docs/RELEASE.md +37 -16
- package/kira_agent.py +21 -8
- package/kira_cli.py +3 -2
- package/kira_config.py +8 -5
- package/kira_jobs.py +87 -21
- package/kira_research_tools.py +1 -1
- package/onchain.cjs +15 -24
- package/package.json +9 -3
- package/pipeline-onchain.cjs +72 -48
- package/public_discovery.py +111 -0
- package/rpc-pool.cjs +216 -0
- package/sources/TOKEN_LIST_LICENSE.txt +674 -0
- package/sources/job-envelope-v1.schema.json +14 -0
- package/sources/job-request-v1.schema.json +6 -0
- package/sources/known-tokens.json +412 -0
- package/sources/rpc-candidates.json +46 -10
- package/viewer/model.py +3 -0
- package/viewer/onboarding.py +2 -1
- package/viewer/refresh-curve-prices.cjs +2 -2
- package/viewer/static/app.js +21 -4
- package/viewer/static/chat-workspace.js +2 -2
- package/viewer/static/index.html +14 -6
- package/viewer/static/jobs.js +68 -19
- package/viewer/static/report.js +2 -2
- package/viewer/static/watching.js +3 -3
- package/viewer/static/workspace-model.js +10 -8
- package/viewer/static/workspace.css +4 -0
- package/wallet.py +151 -27
package/README.md
CHANGED
|
@@ -43,12 +43,11 @@ For a viewer without wallet or research actions, use `kira start --read-only`.
|
|
|
43
43
|
Prefer an archive? [GitHub releases](https://github.com/realproject7/kira-wallet/releases/tag/v0.1.2)
|
|
44
44
|
include the same package and its checksum.
|
|
45
45
|
|
|
46
|
-
1. **
|
|
47
|
-
ERC20 discovery.
|
|
46
|
+
1. **Review optional coverage.** Free research is enabled by default. In **Workspace settings**, connect Alchemy for broader
|
|
47
|
+
ERC20 discovery. Free token sources have limited coverage; incomplete coverage
|
|
48
48
|
stays visible. An AI or browser wallet connection does not enable an indexer.
|
|
49
49
|
2. **Add a watching wallet.** Paste a public address and give it a name. Add more
|
|
50
|
-
wallets whenever you need them.
|
|
51
|
-
offers limited research of native and Mint Club assets.
|
|
50
|
+
wallets whenever you need them. The form starts free research of native, common tokens and Mint Club assets, with keyless discovery on supported networks. First balances appear before detailed research finishes.
|
|
52
51
|
3. **Connect your AI.** Install and sign in to the
|
|
53
52
|
[Codex CLI](https://developers.openai.com/codex/cli) or
|
|
54
53
|
[Claude Code](https://code.claude.com/docs/en/quickstart), then choose your
|
|
@@ -140,3 +139,14 @@ From source, use `node bin/kira.cjs` in place of `kira`.
|
|
|
140
139
|
Original code and Kira character assets are available under the [MIT license](LICENSE).
|
|
141
140
|
Third-party artwork and references retain their own terms; see
|
|
142
141
|
[Third-party notices](THIRD_PARTY_NOTICES.md).
|
|
142
|
+
|
|
143
|
+
### Token coverage and optional Alchemy setup
|
|
144
|
+
|
|
145
|
+
Kira uses free public RPC with bounded fallback and checks a selected common-token
|
|
146
|
+
list alongside native assets and Mint Club. Other ERC20 holdings can be missing.
|
|
147
|
+
Incomplete results show recovery guidance on Home and the wallet page. Connect
|
|
148
|
+
your own Alchemy account for broader discovery on supported networks, then
|
|
149
|
+
refresh holdings. Public RPC remains the first choice for ordinary reads;
|
|
150
|
+
Alchemy is a backup and supplies the dedicated token inventory API. See the
|
|
151
|
+
[step-by-step Alchemy guide](docs/ALCHEMY_SETUP.md) and
|
|
152
|
+
[RPC behavior](docs/FREE_RPC.md).
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -28,3 +28,9 @@ identifies the OWS wallet-creation integration without implying endorsement.
|
|
|
28
28
|
Its retrieval date and source digest are in `site/assets/ows-artwork-source.json`.
|
|
29
29
|
|
|
30
30
|
CASHCAT, BLAST and USDB artwork in the public reconstructed demo comes from lpTOKEN.fun token metadata, DEX Screener and CoinGecko. Token marks belong to their respective owners and identify the assets without implying affiliation or endorsement. The source URLs and chain-specific contract identities are recorded in `site/assets/token-artwork-sources.json`.
|
|
31
|
+
|
|
32
|
+
The factual token inventory in `sources/known-tokens.json` includes selected
|
|
33
|
+
chain/contract identities from Uniswap default-token-list at commit
|
|
34
|
+
583cb696cc15778536fe0ddd416de5bd81be2023. The upstream references retain
|
|
35
|
+
GPL-3.0 terms in `sources/TOKEN_LIST_LICENSE.txt`. Per-contract provenance is
|
|
36
|
+
recorded in the catalog. No upstream executable code or artwork is included.
|
package/docs/AGENT_TOOLS.md
CHANGED
|
@@ -60,3 +60,16 @@ through the user's CLI; local storage does not imply an offline model.
|
|
|
60
60
|
|
|
61
61
|
See [the conversation contract](ONBOARDING_CHAT_CONTRACT.md).
|
|
62
62
|
The standalone stdio MCP adapter above remains read-only and separate.
|
|
63
|
+
|
|
64
|
+
Native responses select the final Codex agent message. Older verified event
|
|
65
|
+
streams without a phase use their last agent message. Commentary cannot become
|
|
66
|
+
a tool request by concatenation. A mixed or malformed request gets one bounded
|
|
67
|
+
correction; no tool executes from it and repeated malformed protocol fails
|
|
68
|
+
without adding raw JSON to conversation history. Turn receipts expose only
|
|
69
|
+
bounded tool names and completed/failed outcomes.
|
|
70
|
+
|
|
71
|
+
Job reads include analysis phase, parent/continuation IDs and real progress
|
|
72
|
+
events. Normalized chain discovery completeness is separate from a job's
|
|
73
|
+
on-chain checkpoint status. Deferred candidates and pending networks are not
|
|
74
|
+
failed reads or zero holdings. Historical observations cannot establish current
|
|
75
|
+
execution, transfers or realized profit.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Connect Alchemy to Kira
|
|
2
|
+
|
|
3
|
+
Kira works with free public RPC by default. It checks native assets, selected
|
|
4
|
+
common token contracts and the Mint Club registry. Other ERC20 holdings may
|
|
5
|
+
be missing. For broader token discovery, connect your own Alchemy account.
|
|
6
|
+
Kira runs these requests locally and does not operate a hosted relay.
|
|
7
|
+
|
|
8
|
+
## Create an Alchemy app
|
|
9
|
+
|
|
10
|
+
1. Sign in to the [Alchemy dashboard](https://dashboard.alchemy.com/).
|
|
11
|
+
A new account may already have a default app. Use it, or open your team
|
|
12
|
+
menu, Team Overview, Apps, then Create new app.
|
|
13
|
+
2. Name the app and select the mainnets you want to research. Check that the
|
|
14
|
+
app has Node API and Portfolio API access for those networks. Create it.
|
|
15
|
+
3. Copy the app API key. The Endpoints tab shows its network URLs. Kira's
|
|
16
|
+
combined Alchemy setup needs the key, so you do not need to copy each URL.
|
|
17
|
+
|
|
18
|
+
These steps follow Alchemy's [official API key guide](https://www.alchemy.com/docs/create-an-api-key),
|
|
19
|
+
checked on October 9, 2026. Dashboard wording can change.
|
|
20
|
+
|
|
21
|
+
## Connect the key locally
|
|
22
|
+
|
|
23
|
+
Create a private directory and file in your terminal:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
mkdir -p ~/.config/kira
|
|
27
|
+
touch ~/.config/kira/alchemy.env
|
|
28
|
+
chmod 600 ~/.config/kira/alchemy.env
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Open the file in a local text editor. On macOS, you can use:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
open -e ~/.config/kira/alchemy.env
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Add this line, replacing `YOUR_KEY` inside the editor:
|
|
38
|
+
|
|
39
|
+
```dotenv
|
|
40
|
+
ALCHEMY_API_KEY=YOUR_KEY
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Save the file, then run:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
kira config import-env --file ~/.config/kira/alchemy.env
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For a non-default workspace, supply its existing `--data-dir` before `config`.
|
|
50
|
+
Kira stores the file reference. Credentials stay outside the browser, chat and
|
|
51
|
+
published analysis. Do not commit this file to a repository. A process
|
|
52
|
+
environment variable with the same name overrides the file value; check that
|
|
53
|
+
if an old key remains active.
|
|
54
|
+
|
|
55
|
+
## Check the connection and refresh
|
|
56
|
+
|
|
57
|
+
Open Workspace settings, then Manage data connection. Select Alchemy and use
|
|
58
|
+
"I added my key · check again". Save the connection. Finding the local key
|
|
59
|
+
does not prove the account, API or network is working.
|
|
60
|
+
|
|
61
|
+
For an existing wallet, choose Refresh this wallet's holdings or Refresh
|
|
62
|
+
holdings on its page. A new analysis confirms access and coverage. Old saved
|
|
63
|
+
analyses retain their original observations and warnings. Saving a connection
|
|
64
|
+
does not register a wallet or start research automatically.
|
|
65
|
+
|
|
66
|
+
## What uses the key
|
|
67
|
+
|
|
68
|
+
Ordinary balances prefer public RPC. After two failed or unavailable public
|
|
69
|
+
providers, Kira tries the configured custom backup within the read deadline.
|
|
70
|
+
Advanced settings can choose custom first or require custom only. Existing
|
|
71
|
+
explicit custom-only restrictions remain in force.
|
|
72
|
+
|
|
73
|
+
Alchemy token discovery uses the key directly. Standard public RPC cannot
|
|
74
|
+
enumerate arbitrary ERC20 holdings. Kira uses Alchemy's
|
|
75
|
+
[Tokens By Wallet endpoint](https://www.alchemy.com/docs/data/portfolio-apis/portfolio-api-endpoints/portfolio-api-endpoints/get-tokens-by-address),
|
|
76
|
+
then verifies discovered candidates with on-chain balance reads.
|
|
77
|
+
|
|
78
|
+
## If tokens are still missing
|
|
79
|
+
|
|
80
|
+
- **Local key unavailable:** confirm the file exists, its variable name matches
|
|
81
|
+
the connection settings, and you ran the import command in the right workspace.
|
|
82
|
+
- **Discovery failed:** check the app's enabled APIs and networks and Alchemy's
|
|
83
|
+
usage dashboard. Correct access or limits, then retry holdings.
|
|
84
|
+
- **Some balances could not be checked:** wait briefly and retry. Public and
|
|
85
|
+
custom providers both have outages and limits. Review Advanced read preferences
|
|
86
|
+
if a custom-only endpoint is unavailable.
|
|
87
|
+
- **Unsupported network:** broader discovery is unavailable there. Connecting
|
|
88
|
+
Alchemy cannot cover every network or every token. Known-contract reads remain
|
|
89
|
+
useful, and missing holdings remain unknown.
|
|
90
|
+
|
|
91
|
+
Alchemy has account allowances and throughput limits. Check the current
|
|
92
|
+
[plans](https://www.alchemy.com/docs/reference/pricing-plans) and API availability
|
|
93
|
+
before selecting a plan. Kira does not create an account, subscribe or upgrade
|
|
94
|
+
it. Public-first balance reads reduce ordinary use of the key; discovery still
|
|
95
|
+
consumes Alchemy allowance. No connection guarantees a complete token inventory.
|
package/docs/CLI.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install -g kira-wallet
|
|
|
10
10
|
kira setup
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The operator published npm version 0.1.
|
|
13
|
+
The operator published npm version 0.1.6. Version 0.1.7 is a preparation candidate. GitHub v0.1.3 remains
|
|
14
14
|
a draft; the previous archive and checksum are available from the
|
|
15
15
|
[0.1.2 GitHub release](https://github.com/realproject7/kira-wallet/releases/tag/v0.1.2).
|
|
16
16
|
Registry publication remains an operator action. The code and original character assets use the MIT license.
|
|
@@ -46,9 +46,9 @@ Published 0.1.4 explains limited discovery before wallet registration and beside
|
|
|
46
46
|
holdings. Missing coverage keeps the portfolio estimate partial. Existing snapshots require a holdings refresh after connecting
|
|
47
47
|
an indexer; a price refresh does not discover missing tokens.
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
open
|
|
51
|
-
|
|
49
|
+
Free research checks known assets, Mint Club and keyless token candidates on supported networks. Alchemy is optional. For broader ERC20 discovery,
|
|
50
|
+
open Custom RPC & token coverage, select Alchemy and follow its local key guide.
|
|
51
|
+
Published 0.1.5 uses one save for Alchemy RPC and discovery; chain overrides
|
|
52
52
|
remain under Advanced. Never paste the key into the browser. `kira doctor`
|
|
53
53
|
checks whether the configured key is available. Configuration alone does not
|
|
54
54
|
prove complete coverage; inspect the recorded results and gaps.
|
|
@@ -68,7 +68,7 @@ authentication. Verified adapter versions are Codex 0.158.x and Claude Code
|
|
|
68
68
|
verified. This is a native CLI connection, with no Kira account, API-key proxy or
|
|
69
69
|
hosted portfolio backend.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
From published 0.1.5, setup opens the existing Account / Permissions / Ready
|
|
72
72
|
modal directly. Choose Codex or Claude, then Use default model or a readable
|
|
73
73
|
model choice. Codex choices come from bounded native metadata; Claude offers
|
|
74
74
|
Sonnet, Opus and Haiku aliases. A catalog is not proof of account access.
|
|
@@ -212,3 +212,12 @@ in session storage. It clears password fields immediately. Recovery keeps the
|
|
|
212
212
|
original encryption passphrase. No signing, key export or account deletion
|
|
213
213
|
endpoint is exposed. OWS absence does not block ordinary address or browser
|
|
214
214
|
wallet onboarding.
|
|
215
|
+
|
|
216
|
+
## Free reads and broader token coverage
|
|
217
|
+
|
|
218
|
+
Public RPC is preferred for ordinary reads, including when a custom backup is
|
|
219
|
+
configured. Advanced settings can select custom first or custom only. For CLI
|
|
220
|
+
configuration, use `kira rpc set --chain 8453 --url-env KIRA_BASE_RPC --priority
|
|
221
|
+
public_first`. Existing custom-only choices remain unchanged. Alchemy token
|
|
222
|
+
discovery uses the configured key directly. See [free RPC behavior](FREE_RPC.md)
|
|
223
|
+
and the [Alchemy setup guide](ALCHEMY_SETUP.md).
|
package/docs/FREE_RPC.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Free RPC reads and token coverage
|
|
2
|
+
|
|
3
|
+
Kira contacts public providers directly from the local research process. No
|
|
4
|
+
Kira relay or shared credential is required. Free public services are best
|
|
5
|
+
effort and can throttle requests or omit historical state.
|
|
6
|
+
|
|
7
|
+
The reviewed default catalog adds alternatives on Ethereum, Base, BNB Chain,
|
|
8
|
+
Polygon, Arbitrum and Optimism. PublicNode is the initial preference. Reserves
|
|
9
|
+
are selected per chain rather than downloaded from an untrusted runtime list.
|
|
10
|
+
The other supported networks retain their existing endpoints.
|
|
11
|
+
|
|
12
|
+
## Request behavior
|
|
13
|
+
|
|
14
|
+
- Chain identity is verified once per endpoint session and again after recovery.
|
|
15
|
+
- One request runs per endpoint. Provider families share one queue and a
|
|
16
|
+
conservative two-second interval across chains. Two chain scans run at once.
|
|
17
|
+
- A logical read has a twelve-second deadline including queues and verification.
|
|
18
|
+
The preferred HTTP attempt has four seconds, reserves at most two seconds.
|
|
19
|
+
Public attempts also have a total budget including verification and pacing,
|
|
20
|
+
leaving half the deadline for a configured personal backup.
|
|
21
|
+
Real fetches are aborted when a deadline expires. HTTP automatic retries are off.
|
|
22
|
+
- At most four endpoint attempts run for a read. Public-first configurations
|
|
23
|
+
reserve an attempt for the personal backup after two public providers.
|
|
24
|
+
- HTTP 429 and JSON-RPC backpressure cool an endpoint for at least sixty seconds.
|
|
25
|
+
Consecutive throttles increase this to at most thirty minutes. Retry-After
|
|
26
|
+
can extend the wait. Other transport failures have a short cooldown.
|
|
27
|
+
- Unsupported methods have a method-specific penalty. Contract reverts do not
|
|
28
|
+
cool an otherwise healthy endpoint. Oversized Multicalls can split; outages and
|
|
29
|
+
throttling cannot create a burst of smaller calls.
|
|
30
|
+
|
|
31
|
+
These are application limits, not promises about a provider's quota or uptime.
|
|
32
|
+
Cooldown observations survive sequential research subprocesses in a bounded
|
|
33
|
+
local cache. Custom endpoints and credentialed URLs are not written there.
|
|
34
|
+
Status screens and onboarding checks do not probe RPC providers.
|
|
35
|
+
|
|
36
|
+
## Snapshot consistency
|
|
37
|
+
|
|
38
|
+
Each chain analysis records a block number and hash. Balance and contract reads
|
|
39
|
+
keep that block. Before a fallback provider reads it, Kira verifies its header
|
|
40
|
+
has the same hash. Every evidence read then uses an EIP-1898 block-hash selector
|
|
41
|
+
with canonical checking. Providers that do not support it cannot supply that
|
|
42
|
+
snapshot's evidence. Conflicting or unavailable evidence stays incomplete.
|
|
43
|
+
No fallback silently substitutes `latest` for a fixed block.
|
|
44
|
+
|
|
45
|
+
Identical concurrent reads share work. Successful fixed-block reads have a
|
|
46
|
+
bounded cache keyed by chain, pinned hash, method and complete parameters,
|
|
47
|
+
including the wallet address. Failed reads are evicted and never become zero.
|
|
48
|
+
Wallet balances are not reused across wallets or new research processes.
|
|
49
|
+
Registry identity caching remains separate from balances.
|
|
50
|
+
|
|
51
|
+
## Default token inventory
|
|
52
|
+
|
|
53
|
+
Native balances and the selected issuer/deployment-backed contracts in
|
|
54
|
+
`sources/known-tokens.json` are checked before cold Mint Club enumeration.
|
|
55
|
+
The catalog has 57 chain/contract identities on eight mainnets. Issuer references
|
|
56
|
+
and selected Uniswap token-list records retain per-contract provenance. The
|
|
57
|
+
upstream list commit and its license are bundled; no untrusted runtime list is
|
|
58
|
+
loaded. Decimals and quantities come from on-chain reads. This remains a bounded
|
|
59
|
+
inventory, not a claim to discover every wrapped or arbitrary token.
|
|
60
|
+
|
|
61
|
+
Default research also uses Routescan without a key on individually verified
|
|
62
|
+
Ethereum, Avalanche and Blast routes. Its documented free access is limited to
|
|
63
|
+
two requests per second and 10,000 calls per day. Kira starts at most one call
|
|
64
|
+
per second, reads at most 20 pages of 100 candidates per chain and spends at most
|
|
65
|
+
25 seconds per enumeration. An isolated HTTP reader enforces a total deadline,
|
|
66
|
+
including DNS and response bodies. Unsafe pagination, outages, malformed data
|
|
67
|
+
and limits keep coverage partial. Provider quantities and prices never replace
|
|
68
|
+
RPC-verified balances. Other Routescan chains are not presumed supported.
|
|
69
|
+
Explicit keyless opt-outs and custom-only preferences remain respected.
|
|
70
|
+
|
|
71
|
+
Initial reports check Base, Ethereum and Blast, up to 128 candidates per chain.
|
|
72
|
+
Selected common contracts take priority. Remaining candidates and networks are
|
|
73
|
+
explicitly pending. A durable background continuation scans every configured
|
|
74
|
+
network, the full Mint Club registry and markets. Registry identity prefixes
|
|
75
|
+
are saved incrementally; balances are never shared between wallets. Batches
|
|
76
|
+
contain at most 128 reads, with splitting only for verified payload limits.
|
|
77
|
+
New initial work takes priority over detailed research. Older same-wallet
|
|
78
|
+
continuations cannot replace newer evidence.
|
|
79
|
+
|
|
80
|
+
Public RPC cannot enumerate all arbitrary ERC20 contracts. Alchemy is an
|
|
81
|
+
optional broader candidate source and backup RPC. Discovery calls made through
|
|
82
|
+
the wallet engine have a 25-second initial or 60-second detailed per-chain
|
|
83
|
+
budget. Native balances, free candidates and Mint Club research remain usable
|
|
84
|
+
without it. Missing or deferred evidence stays unknown. Persistent coverage
|
|
85
|
+
notices distinguish pending work from failed reads and offer retry or optional
|
|
86
|
+
[Alchemy setup](ALCHEMY_SETUP.md).
|
|
87
|
+
|
|
88
|
+
Keyless sources: [Routescan addresses](https://routescan.io/docs/api/addresses),
|
|
89
|
+
[API access](https://routescan.io/docs/plans-and-limits/api-keys-and-pricing),
|
|
90
|
+
[rate limits](https://routescan.io/docs/plans-and-limits/rate-limits).
|
|
91
|
+
|
|
92
|
+
## Read preferences
|
|
93
|
+
|
|
94
|
+
Public first is the default even when a custom connection is configured.
|
|
95
|
+
Advanced settings provide custom first and custom only. Configurations without
|
|
96
|
+
the new priority field use public first; an existing explicit custom-only choice
|
|
97
|
+
continues to exclude public endpoints. RPC priority does not change the dedicated
|
|
98
|
+
Alchemy discovery request.
|
|
99
|
+
|
|
100
|
+
CLI example using an existing local endpoint variable:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
kira rpc set --chain 8453 --url-env KIRA_BASE_RPC --priority public_first
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Primary references: [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898),
|
|
107
|
+
[PublicNode](https://www.publicnode.com/),
|
|
108
|
+
[dRPC limits](https://drpc.org/docs/howitworks/ratelimiting),
|
|
109
|
+
[1RPC networks](https://docs.1rpc.io/overview/supported-networks),
|
|
110
|
+
[Circle contracts](https://developers.circle.com/stablecoins/usdc-contract-addresses),
|
|
111
|
+
[Tether contracts](https://tether.to/en/supported-protocols/),
|
|
112
|
+
[Uniswap Arbitrum deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-arbitrum-deployments).
|
package/docs/JOB_CONTRACT.md
CHANGED
|
@@ -121,3 +121,27 @@ its projection receipt without another provider request.
|
|
|
121
121
|
|
|
122
122
|
The read-only stdio MCP adapter uses the same job and snapshot service. It has
|
|
123
123
|
no mutation tools and requires separate operator-approved client setup.
|
|
124
|
+
|
|
125
|
+
## Initial evidence and continuations in 0.1.7
|
|
126
|
+
|
|
127
|
+
A valid wallet admission records its identity under a short registry lock.
|
|
128
|
+
Idempotent replay repairs missing admission without undoing later name edits.
|
|
129
|
+
New analysis jobs have `analysis_phase: baseline`. The first usable chain
|
|
130
|
+
publishes an immutable `initial/` snapshot; the running job can reference it
|
|
131
|
+
without claiming that the job is finished. The baseline publishes its own final
|
|
132
|
+
partial snapshot and admits exactly one durable `enrichment` continuation with
|
|
133
|
+
`parent_job_id`. The parent records `continuation_id`.
|
|
134
|
+
|
|
135
|
+
Baseline work runs before enrichment. New baseline admission can preempt a
|
|
136
|
+
running continuation. Saved chain evidence and verified registry identity
|
|
137
|
+
prefixes survive; an interrupted registry batch is read again. A newer request
|
|
138
|
+
for the same wallet supersedes older detailed work. Generation checks prevent
|
|
139
|
+
an older result from replacing the latest pointer, while preserving historical
|
|
140
|
+
evidence. Explicit cancellation of baseline prevents automatic continuation.
|
|
141
|
+
|
|
142
|
+
`onchain_progress` events identify the actual operation, chain, checked count
|
|
143
|
+
and known total. `chain.status: complete` concerns the on-chain checkpoint.
|
|
144
|
+
Normalized wallet `complete` concerns general token discovery. Registry coverage,
|
|
145
|
+
candidate failures, deferred candidates and pending RPC reads are separate facts.
|
|
146
|
+
These flags do not prove exhaustive holdings. First results can be read while
|
|
147
|
+
background work remains active.
|
package/docs/RELEASE.md
CHANGED
|
@@ -44,19 +44,20 @@ RPC failures show affected networks, retry guidance and a settings action.
|
|
|
44
44
|
Failed candidate balance reads keep the saved result and valuation partial
|
|
45
45
|
even when general token discovery succeeded.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
Published **0.1.5** opens the existing setup modal directly, adds Codex and
|
|
48
|
+
Claude model choices, exposes model and permission changes in Workspace settings,
|
|
49
|
+
and provides one Alchemy connection save. Its registry version was confirmed on
|
|
50
|
+
2026-10-09. Published package bytes remain immutable.
|
|
51
|
+
|
|
52
|
+
Published **0.1.6** adds a paced local RPC pool, core-chain public
|
|
53
|
+
alternatives, public-first custom backup, fixed-block hash checks and a small
|
|
54
|
+
known-token catalog. Home and wallet pages display incomplete coverage with an
|
|
55
|
+
Alchemy setup action. The settings guide explains account setup, private local
|
|
56
|
+
key import and an explicit holdings refresh. Missing or malformed discovery data
|
|
57
|
+
cannot become a completed empty inventory.
|
|
58
|
+
|
|
59
|
+
Version 0.1.6 is published and immutable. The showcase remains a separate deployment. See
|
|
60
|
+
[free RPC behavior](FREE_RPC.md) and [Alchemy setup](ALCHEMY_SETUP.md).
|
|
60
61
|
|
|
61
62
|
The operator published npm **0.1.2** on 2026-10-05. Its registry archive was
|
|
62
63
|
downloaded and matched the reviewed GitHub archive above, including SHA-256,
|
|
@@ -78,7 +79,7 @@ The earlier unpublished 0.1.2 candidate is preserved in the ignored
|
|
|
78
79
|
`dist/preserved-0.1.2-bad8f02/` directory. Use the current `dist/release.json`
|
|
79
80
|
and its matching archive for publication; do not mix manifests from candidates.
|
|
80
81
|
|
|
81
|
-
Keep GitHub v0.1.1, its tag and its released archive immutable. Versions 0.1.2, 0.1.3 and 0.1.
|
|
82
|
+
Keep GitHub v0.1.1, its tag and its released archive immutable. Versions 0.1.2, 0.1.3, 0.1.4, 0.1.5 and 0.1.6 are also published and immutable. Do not rebuild them from later documentation
|
|
82
83
|
commits. Future package changes need a new version. Release preparation does not
|
|
83
84
|
publish a GitHub release, merge PR 19, promote the website or publish to npm.
|
|
84
85
|
Registry publication remains operator-only. The coding agent never publishes.
|
|
@@ -93,18 +94,38 @@ python3 scripts/prepare-release.py
|
|
|
93
94
|
```
|
|
94
95
|
|
|
95
96
|
`prepare-release.py` scans the package boundary and creates
|
|
96
|
-
`dist/kira-wallet-0.1.
|
|
97
|
+
`dist/kira-wallet-0.1.7.tgz`. The ignored `dist/release.json` records its source
|
|
97
98
|
commit, SHA-256 and member count. It never publishes. After reviewing that
|
|
98
99
|
manifest, the operator's final command from the project root is:
|
|
99
100
|
|
|
100
101
|
```sh
|
|
101
|
-
npm publish ./dist/kira-wallet-0.1.
|
|
102
|
+
npm publish ./dist/kira-wallet-0.1.7.tgz --access public
|
|
102
103
|
```
|
|
103
104
|
|
|
104
105
|
Use the operator's npm account and complete authentication or OTP personally.
|
|
105
106
|
After publication, verify the registry archive and perform a fresh install
|
|
106
107
|
before marking the new onboarding flow as available to npm users.
|
|
107
108
|
|
|
109
|
+
## Proposed 0.1.7 behavior
|
|
110
|
+
|
|
111
|
+
The candidate enables useful keyless research by default, expands the curated
|
|
112
|
+
contract inventory and separates first recorded balances from exhaustive
|
|
113
|
+
background research. Pending candidates, registry work and other networks stay
|
|
114
|
+
visible. Current wallet evidence cannot roll back when an older continuation
|
|
115
|
+
resumes. See [coverage and limits](FREE_RPC.md).
|
|
116
|
+
|
|
117
|
+
Codex uses the final native message rather than joined commentary. Mixed tool
|
|
118
|
+
protocol receives one bounded correction and is never rendered as a completed
|
|
119
|
+
answer. Claude retains its restricted native adapter. Tool receipts contain
|
|
120
|
+
names and outcomes, without raw arguments. Job checkpoints and normalized token
|
|
121
|
+
discovery flags have separate meanings. Imported connection references reconcile
|
|
122
|
+
with untouched settings fields while preserving edited drafts.
|
|
123
|
+
|
|
124
|
+
The next archive is **0.1.7**, unpublished until the operator runs the command.
|
|
125
|
+
Release readiness requires the repository suite, clean installation, source and
|
|
126
|
+
history privacy scans, independent review and the frozen archive manifest.
|
|
127
|
+
No live-extension or human passphrase acceptance is inferred from these checks.
|
|
128
|
+
|
|
108
129
|
## Verified 0.1.0 publication
|
|
109
130
|
|
|
110
131
|
The operator published 0.1.0, verified on 2026-10-04. The registry archive has
|
package/kira_agent.py
CHANGED
|
@@ -42,7 +42,7 @@ SYSTEM = ('You are Kira, a careful wallet research partner. Answer in the langua
|
|
|
42
42
|
'and full-balance output only when a validated quote exists. DEX pool TVL is not a sell quote. '
|
|
43
43
|
'Missing execution quotes mean sale proceeds, fees, gas and price impact are unknown. '
|
|
44
44
|
'For network questions, group by wallet and distinguish known assets from missing coverage. '
|
|
45
|
-
'
|
|
45
|
+
'In normalized wallet facts, chain complete means general ERC20 discovery was checked. In job chains, status complete means an on-chain checkpoint finished. These are different stages. Neither flag alone proves all holdings are known. registry_complete and candidate_balance_errors describe separate read coverage. An indexer check and unavailable RPC are separate coverage facts, not conflicting records. '
|
|
46
46
|
'An explicit chains.native_balance of zero is an observed native balance at its recorded time and block; null is unknown. Empty positive-holding inventories do not erase these observations. '
|
|
47
47
|
'For saved-analysis comparisons, use snapshots_compare and read both snapshots. coverage_changed compares full evidence, including times and blocks, not just network status flags. price_references_changed may include changed reference values or times, not balances. '
|
|
48
48
|
'Snapshot reads are normalized evidence. Compare chain observations and snapshot_price_references; never claim these are the only raw fields that changed. '
|
|
@@ -140,7 +140,7 @@ def wallet_facts(wallets, *, pool_budget=40_000):
|
|
|
140
140
|
for wallet in wallets:
|
|
141
141
|
row = pick(wallet,('address','tags','name','analysed_at','prices_at','balance_observed_at','known_value_usd','unpriced_count','status'))
|
|
142
142
|
if not wallet.get('analysed_at'): row['known_value_usd']=None
|
|
143
|
-
row['chains'] = [pick(c,('id','name','environment','complete','rpc_available','native_symbol','native_balance','native_observed_at','native_block_number','registry_block_number')) for c in wallet['chains']]
|
|
143
|
+
row['chains'] = [pick(c,('id','name','environment','complete','rpc_available','native_symbol','native_balance','native_observed_at','native_block_number','registry_block_number','discovery_status','registry_complete','registry_phase','rpc_pending','candidate_balance_errors','candidate_deferred')) for c in wallet['chains']]
|
|
144
144
|
row['snapshot_price_references'] = wallet.get('snapshot_price_references',{})
|
|
145
145
|
row['assets'] = []
|
|
146
146
|
for asset in wallet['assets']:
|
|
@@ -211,11 +211,14 @@ def run_native(config, prompt, cancel, *, timeout=180):
|
|
|
211
211
|
else:
|
|
212
212
|
events = [json.loads(line) for line in output.splitlines() if line.strip()]
|
|
213
213
|
if not any(e.get('type') == 'turn.completed' for e in events): raise ValueError()
|
|
214
|
-
|
|
214
|
+
messages = [e['item'] for e in events if e.get('type') == 'item.completed' and e.get('item',{}).get('type') == 'agent_message']
|
|
215
|
+
finals = [m for m in messages if m.get('phase')=='final_answer']
|
|
216
|
+
# Older verified CLIs omit phase. Only their last message is final.
|
|
217
|
+
answer = (finals or [m for m in messages if not m.get('phase')])[-1].get('text','') if finals or any(not m.get('phase') for m in messages) else None
|
|
215
218
|
if not isinstance(answer,str) or not answer.strip() or len(answer) > 60_000: raise ValueError()
|
|
216
219
|
return answer.strip()
|
|
217
220
|
except JobError: raise
|
|
218
|
-
except (ValueError,KeyError,subprocess.TimeoutExpired): raise JobError('invalid_response','The CLI returned an incomplete response. Try again or choose another supported model.') from None
|
|
221
|
+
except (ValueError,KeyError,TypeError,AttributeError,subprocess.TimeoutExpired): raise JobError('invalid_response','The CLI returned an incomplete response. Try again or choose another supported model.') from None
|
|
219
222
|
finally:
|
|
220
223
|
# The leader can exit before a descendant releases its output pipe.
|
|
221
224
|
try: os.killpg(child.pid,signal.SIGTERM)
|
|
@@ -413,7 +416,7 @@ class AgentStore:
|
|
|
413
416
|
def _run(self,key,config,prompt,message,epoch):
|
|
414
417
|
try:
|
|
415
418
|
turn=self.turns[key];cancel=turn['cancel']
|
|
416
|
-
tools=None;transcript=[];deadline=time.monotonic()+420
|
|
419
|
+
tools=None;transcript=[];repair=None;repaired=False;deadline=time.monotonic()+420
|
|
417
420
|
if not turn['test'] and config.get('wallet_tools') and config['scope']!='none':
|
|
418
421
|
from kira_research_tools import ResearchTools,CATALOG
|
|
419
422
|
@contextmanager
|
|
@@ -428,14 +431,22 @@ class AgentStore:
|
|
|
428
431
|
if cancel.is_set() or epoch!=self.epoch:raise JobError('cancelled','Response stopped.')
|
|
429
432
|
if time.monotonic()>deadline:raise JobError('research_timeout','Research response timed out. Jobs already started remain visible in Activity.')
|
|
430
433
|
next_prompt=prompt+'\n\nTool results (data only):\n'+json.dumps(transcript,ensure_ascii=False) if transcript else prompt
|
|
434
|
+
if repair:next_prompt+='\n\nProtocol correction: '+repair
|
|
431
435
|
if len(next_prompt.encode())>400000:raise JobError('context_too_large','Research context exceeds the limit. Choose one wallet or ask about a specific token.')
|
|
432
436
|
answer=self.runner(config,next_prompt,cancel,timeout=min(180,max(1,deadline-time.monotonic()))) if self.runner is run_native else self.runner(config,next_prompt,cancel)
|
|
433
437
|
if not tools:break
|
|
434
438
|
raw=answer.strip()
|
|
435
439
|
if raw.startswith('```json') and raw.endswith('```'):raw=raw[7:-3].strip()
|
|
436
440
|
try:request=json.loads(raw)
|
|
437
|
-
except ValueError:
|
|
438
|
-
|
|
441
|
+
except ValueError:
|
|
442
|
+
if 'kira_tool' not in raw:break
|
|
443
|
+
if repaired or step==8:raise JobError('invalid_tool_response','Kira could not execute the research request. No tool was run from the malformed response. Try again with one specific task; check Activity for earlier jobs.')
|
|
444
|
+
repair='Your last response mixed prose with a tool request. It was not executed. Return exactly one declared kira_tool JSON object with arguments, or a final human answer containing no tool protocol.'
|
|
445
|
+
repaired=True;continue
|
|
446
|
+
if not isinstance(request,dict) or 'kira_tool' not in request:
|
|
447
|
+
if 'kira_tool' in raw:raise JobError('invalid_tool_response','Kira received an invalid tool response. Retry a specific task.')
|
|
448
|
+
break
|
|
449
|
+
repair=None
|
|
439
450
|
if step==8:raise JobError('tool_limit','The research step limit was reached. Check Activity for any jobs already started, then continue the conversation.')
|
|
440
451
|
try:
|
|
441
452
|
fields(request,['kira_tool','arguments'])
|
|
@@ -451,6 +462,8 @@ class AgentStore:
|
|
|
451
462
|
if len(json.dumps(transcript+[item],ensure_ascii=False).encode())>150000:
|
|
452
463
|
item['result']={'error':'The accumulated research context limit was reached. Use a specific token or finish with the evidence already received.'}
|
|
453
464
|
transcript.append(item)
|
|
465
|
+
with self.lock:
|
|
466
|
+
self.turns[key].setdefault('tool_calls',[]).append({'name':request['kira_tool'],'status':'failed' if isinstance(result,dict) and result.get('error') else 'completed'})
|
|
454
467
|
with self.lock:self.tool_status='Kira is analysing the results…'
|
|
455
468
|
|
|
456
469
|
with self.lock:
|
|
@@ -474,7 +487,7 @@ class AgentStore:
|
|
|
474
487
|
def read(self,key):
|
|
475
488
|
with self.lock:
|
|
476
489
|
if key not in self.turns:raise JobError('not_found','This response is no longer available. Start a new conversation.')
|
|
477
|
-
return {**{k:self.turns[key][k] for k in ('id','state','error','answer','test','message','conversation_id')},'tool_status':self.tool_status if self.active==key else None}
|
|
490
|
+
return {**{k:self.turns[key][k] for k in ('id','state','error','answer','test','message','conversation_id')},'tool_calls':self.turns[key].get('tool_calls',[]),'tool_status':self.tool_status if self.active==key else None}
|
|
478
491
|
|
|
479
492
|
def cancel(self,key):
|
|
480
493
|
with self.lock:
|
package/kira_cli.py
CHANGED
|
@@ -172,7 +172,7 @@ def main():
|
|
|
172
172
|
imp=configsub.add_parser('import-env');imp.add_argument('--file',required=True);imp.add_argument('--key-env',default='ALCHEMY_API_KEY')
|
|
173
173
|
rpc=sub.add_parser('rpc');rpcsub=rpc.add_subparsers(dest='setting',required=True)
|
|
174
174
|
rpcsub.add_parser('public')
|
|
175
|
-
custom=rpcsub.add_parser('set');custom.add_argument('--chain',type=int,required=True);custom.add_argument('--url-env',required=True);fallback=custom.add_mutually_exclusive_group();fallback.add_argument('--public-fallback',action='store_true',default=None);fallback.add_argument('--custom-only',dest='public_fallback',action='store_false')
|
|
175
|
+
custom=rpcsub.add_parser('set');custom.add_argument('--chain',type=int,required=True);custom.add_argument('--url-env',required=True);custom.add_argument('--priority',choices=['public_first','custom_first']);fallback=custom.add_mutually_exclusive_group();fallback.add_argument('--public-fallback',action='store_true',default=None);fallback.add_argument('--custom-only',dest='public_fallback',action='store_false')
|
|
176
176
|
discovery=sub.add_parser('discovery');discovery.add_argument('provider',choices=['none','alchemy']);discovery.add_argument('--key-env',default='ALCHEMY_API_KEY');discovery.add_argument('--explorers',action='store_true')
|
|
177
177
|
args=parser.parse_args();root=Path(args.data_dir).expanduser().resolve();os.environ['KIRA_DATA_DIR']=str(root)
|
|
178
178
|
if sys.version_info<(3,11):raise ValueError('Python 3.11 or newer is required.')
|
|
@@ -235,10 +235,11 @@ def main():
|
|
|
235
235
|
from kira_config import provider_config
|
|
236
236
|
cfg=provider_config(cfg,'alchemy',args.key_env)
|
|
237
237
|
cfg['secret_env_file']=str(file);cfg['discovery']['explorers']=True
|
|
238
|
-
elif args.command=='discovery':cfg['discovery']={'provider':args.provider,'key_env':args.key_env,'explorers':args.explorers}
|
|
238
|
+
elif args.command=='discovery':cfg['discovery']={**cfg['discovery'],'provider':args.provider,'key_env':args.key_env,'explorers':args.explorers}
|
|
239
239
|
elif args.setting=='public':cfg['rpc']['mode']='public'
|
|
240
240
|
else:
|
|
241
241
|
cfg['rpc'].update(mode='custom')
|
|
242
|
+
if args.priority:cfg['rpc']['priority']=args.priority
|
|
242
243
|
if args.public_fallback is not None:cfg['rpc']['allow_public_fallback']=args.public_fallback
|
|
243
244
|
cfg['rpc']['chains'][str(args.chain)]={'url_env':args.url_env}
|
|
244
245
|
# Validate before replacing the user's working configuration.
|
package/kira_config.py
CHANGED
|
@@ -16,8 +16,8 @@ def config_path():
|
|
|
16
16
|
return Path(os.environ.get('KIRA_CONFIG', data_root()/'.kira.local.json')).expanduser()
|
|
17
17
|
|
|
18
18
|
def default_config():
|
|
19
|
-
return {'schema_version':1,'rpc':{'mode':'public','allow_public_fallback':True,'chains':{}},
|
|
20
|
-
'discovery':{'provider':'none','key_env':'ALCHEMY_API_KEY','explorers':False}}
|
|
19
|
+
return {'schema_version':1,'rpc':{'mode':'public','allow_public_fallback':True,'priority':'public_first','chains':{}},
|
|
20
|
+
'discovery':{'provider':'none','key_env':'ALCHEMY_API_KEY','explorers':False,'public':True}}
|
|
21
21
|
|
|
22
22
|
def provider_config(config, provider, key_env):
|
|
23
23
|
"""One settings transition. Preserve explicit fallback and custom overrides."""
|
|
@@ -44,7 +44,9 @@ def load_config():
|
|
|
44
44
|
raise ValueError('Invalid RPC configuration.')
|
|
45
45
|
if not isinstance(discovery,dict) or discovery.get('provider') not in ('none','alchemy') or type(discovery.get('explorers',False)) is not bool:
|
|
46
46
|
raise ValueError('Invalid discovery configuration.')
|
|
47
|
-
if
|
|
47
|
+
if rpc.get('priority','public_first') not in ('public_first','custom_first'):raise ValueError('Invalid RPC priority.')
|
|
48
|
+
if type(discovery.get('public',True)) is not bool:raise ValueError('Invalid public discovery preference.')
|
|
49
|
+
if set(rpc)-{'mode','allow_public_fallback','priority','chains'} or set(discovery)-{'provider','key_env','explorers','public'}:raise ValueError('Unknown provider configuration fields.')
|
|
48
50
|
if any(not isinstance(row,dict) or set(row)-{'url_env','alchemy_network'} for row in rpc['chains'].values()):raise ValueError('Unknown RPC endpoint fields.')
|
|
49
51
|
for name in [discovery.get('key_env'),*[row.get('url_env') if isinstance(row,dict) else None for row in rpc['chains'].values()]]:
|
|
50
52
|
if not isinstance(name,str) or not re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]*',name):raise ValueError('Credentials must use valid environment references.')
|
|
@@ -97,7 +99,8 @@ def endpoints(network,cfg=None):
|
|
|
97
99
|
# New setups default to automatic fallback. Preserve an explicit existing
|
|
98
100
|
# opt-out for operators who require custom providers only.
|
|
99
101
|
if not rpc['allow_public_fallback']:return urls
|
|
100
|
-
|
|
102
|
+
public=network.get('public_rpc') or []
|
|
103
|
+
urls=public+urls if rpc.get('priority','public_first')=='public_first' else urls+public
|
|
101
104
|
return list(dict.fromkeys(urls))
|
|
102
105
|
|
|
103
106
|
def runtime():
|
|
@@ -105,7 +108,7 @@ def runtime():
|
|
|
105
108
|
try: values=secret_values(cfg)
|
|
106
109
|
except ValueError: values={}
|
|
107
110
|
return {'endpoints':{str(n['chain_id']):endpoints(n,cfg) for n in networks},
|
|
108
|
-
'secrets':list(values.values()),'data_root':str(data_root())}
|
|
111
|
+
'secrets':list(values.values()),'data_root':str(data_root()),'health_file':str(data_root()/'cache/rpc-health.json')}
|
|
109
112
|
|
|
110
113
|
if __name__=='__main__':
|
|
111
114
|
# Internal child-process channel only. The user CLI never emits this payload.
|