kira-wallet 0.1.4 → 0.1.6
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 +11 -0
- package/docs/ALCHEMY_SETUP.md +95 -0
- package/docs/CLI.md +27 -11
- package/docs/FREE_RPC.md +85 -0
- package/docs/JOB_CONTRACT.md +13 -1
- package/docs/ONBOARDING_CHAT_CONTRACT.md +34 -1
- package/docs/RELEASE.md +19 -9
- package/kira_agent.py +14 -0
- package/kira_cli.py +5 -5
- package/kira_config.py +19 -4
- package/kira_jobs.py +20 -6
- package/kira_models.py +86 -0
- package/onchain.cjs +15 -24
- package/package.json +8 -3
- package/pipeline-onchain.cjs +24 -18
- package/rpc-pool.cjs +216 -0
- package/sources/job-envelope-v1.schema.json +2 -1
- package/sources/job-request-v1.schema.json +49 -0
- package/sources/known-tokens.json +77 -0
- package/sources/rpc-candidates.json +46 -10
- package/viewer/onboarding.py +4 -2
- package/viewer/refresh-curve-prices.cjs +2 -2
- package/viewer/server.py +3 -1
- package/viewer/static/agent.js +65 -14
- package/viewer/static/app.js +16 -2
- package/viewer/static/index.html +37 -6
- package/viewer/static/jobs.js +134 -9
- package/viewer/static/report.js +3 -3
- package/viewer/static/watching.js +1 -1
- package/viewer/static/workspace-model.js +6 -5
- package/viewer/static/workspace.css +15 -3
- package/wallet.py +22 -7
package/README.md
CHANGED
|
@@ -140,3 +140,14 @@ From source, use `node bin/kira.cjs` in place of `kira`.
|
|
|
140
140
|
Original code and Kira character assets are available under the [MIT license](LICENSE).
|
|
141
141
|
Third-party artwork and references retain their own terms; see
|
|
142
142
|
[Third-party notices](THIRD_PARTY_NOTICES.md).
|
|
143
|
+
|
|
144
|
+
### Token coverage and optional Alchemy setup
|
|
145
|
+
|
|
146
|
+
Kira uses free public RPC with bounded fallback and checks a selected common-token
|
|
147
|
+
list alongside native assets and Mint Club. Other ERC20 holdings can be missing.
|
|
148
|
+
Incomplete results show recovery guidance on Home and the wallet page. Connect
|
|
149
|
+
your own Alchemy account for broader discovery on supported networks, then
|
|
150
|
+
refresh holdings. Public RPC remains the first choice for ordinary reads;
|
|
151
|
+
Alchemy is a backup and supplies the dedicated token inventory API. See the
|
|
152
|
+
[step-by-step Alchemy guide](docs/ALCHEMY_SETUP.md) and
|
|
153
|
+
[RPC behavior](docs/FREE_RPC.md).
|
|
@@ -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.5. Version 0.1.6 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.
|
|
@@ -42,14 +42,14 @@ address or use the browser wallet picker. Registration starts one explicit
|
|
|
42
42
|
research job; follow it in Activity and read the saved portfolio report.
|
|
43
43
|
No signature, seed phrase or private key is needed.
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
holdings. Missing coverage keeps the portfolio estimate partial.
|
|
47
|
-
published to npm. Existing snapshots require a holdings refresh after connecting
|
|
45
|
+
Published 0.1.4 explains limited discovery before wallet registration and beside
|
|
46
|
+
holdings. Missing coverage keeps the portfolio estimate partial. Existing snapshots require a holdings refresh after connecting
|
|
48
47
|
an indexer; a price refresh does not discover missing tokens.
|
|
49
48
|
|
|
50
49
|
Public RPC checks known assets and Mint Club. For broader ERC20 discovery,
|
|
51
|
-
open
|
|
52
|
-
|
|
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
|
+
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.
|
|
55
55
|
|
|
@@ -68,8 +68,12 @@ 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
|
-
|
|
72
|
-
|
|
71
|
+
From published 0.1.5, setup opens the existing Account / Permissions / Ready
|
|
72
|
+
modal directly. Choose Codex or Claude, then Use default model or a readable
|
|
73
|
+
model choice. Codex choices come from bounded native metadata; Claude offers
|
|
74
|
+
Sonnet, Opus and Haiku aliases. A catalog is not proof of account access.
|
|
75
|
+
Advanced accepts a custom identifier and preserves saved identifiers absent
|
|
76
|
+
from the catalog. Workspace settings reopens the same selector and permissions. Choose no automatic wallet context, one registered wallet,
|
|
73
77
|
or the whole recorded portfolio. A generic response check sends no wallet data
|
|
74
78
|
and must pass before these settings are saved.
|
|
75
79
|
|
|
@@ -79,7 +83,10 @@ and contract identities, timestamps, unknown prices and coverage. Credentials,
|
|
|
79
83
|
RPC endpoints, raw provider errors and local paths are excluded. Changing the
|
|
80
84
|
provider, model, context or selected wallet creates a new conversation.
|
|
81
85
|
|
|
82
|
-
|
|
86
|
+
New setup in 0.1.5 recommends saving history and preselects it. Existing saved
|
|
87
|
+
true and false choices are restored exactly. Saving lets you reopen chats after
|
|
88
|
+
restart; it does not expand model memory or wallet access. The choice and
|
|
89
|
+
research permission remain editable in Workspace settings. Kira-local history uses private `conversations/` files. With history
|
|
83
90
|
off, conversations and drafts stay in memory. A new server process starts a fresh
|
|
84
91
|
conversation; saved files remain available locally and are not automatically
|
|
85
92
|
replayed. Native CLI, administrator policy and provider data policies remain a
|
|
@@ -135,8 +142,8 @@ kira config import-env --file /absolute/private/rpc.env --key-env ALCHEMY_API_KE
|
|
|
135
142
|
```
|
|
136
143
|
|
|
137
144
|
The import references the file instead of copying keys. It configures Alchemy
|
|
138
|
-
RPC and portfolio discovery
|
|
139
|
-
|
|
145
|
+
RPC and portfolio discovery together, preserving existing custom chain overrides
|
|
146
|
+
and explicit fallback preferences. New configurations allow public fallback. Environment overrides the file. Missing files or keys
|
|
140
147
|
produce limited coverage; malformed configuration fails with safe errors.
|
|
141
148
|
The import does not contact providers. Private settings are never served.
|
|
142
149
|
|
|
@@ -205,3 +212,12 @@ in session storage. It clears password fields immediately. Recovery keeps the
|
|
|
205
212
|
original encryption passphrase. No signing, key export or account deletion
|
|
206
213
|
endpoint is exposed. OWS absence does not block ordinary address or browser
|
|
207
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,85 @@
|
|
|
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 small list includes USDC on seven supported mainnets, USDT on Ethereum and
|
|
56
|
+
Avalanche, and WETH on Arbitrum. Decimals and quantities come from on-chain
|
|
57
|
+
reads. This list does not cover all common tokens or all wrapped/bridged variants.
|
|
58
|
+
|
|
59
|
+
The full Mint Club registry is still scanned. Public RPC cannot enumerate all
|
|
60
|
+
arbitrary ERC20 contracts held by an address. Discovery remains incomplete
|
|
61
|
+
without a working indexer on that network. Incomplete holdings show a persistent
|
|
62
|
+
notice on Home and the wallet page, with a path to
|
|
63
|
+
[Alchemy setup](ALCHEMY_SETUP.md) and an explicit holdings refresh.
|
|
64
|
+
|
|
65
|
+
## Read preferences
|
|
66
|
+
|
|
67
|
+
Public first is the default even when a custom connection is configured.
|
|
68
|
+
Advanced settings provide custom first and custom only. Configurations without
|
|
69
|
+
the new priority field use public first; an existing explicit custom-only choice
|
|
70
|
+
continues to exclude public endpoints. RPC priority does not change the dedicated
|
|
71
|
+
Alchemy discovery request.
|
|
72
|
+
|
|
73
|
+
CLI example using an existing local endpoint variable:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
kira rpc set --chain 8453 --url-env KIRA_BASE_RPC --priority public_first
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Primary references: [EIP-1898](https://eips.ethereum.org/EIPS/eip-1898),
|
|
80
|
+
[PublicNode](https://www.publicnode.com/),
|
|
81
|
+
[dRPC limits](https://drpc.org/docs/howitworks/ratelimiting),
|
|
82
|
+
[1RPC networks](https://docs.1rpc.io/overview/supported-networks),
|
|
83
|
+
[Circle contracts](https://developers.circle.com/stablecoins/usdc-contract-addresses),
|
|
84
|
+
[Tether contracts](https://tether.to/en/supported-protocols/),
|
|
85
|
+
[Uniswap Arbitrum deployments](https://developers.uniswap.org/docs/protocols/v3/deployments/v3-arbitrum-deployments).
|
package/docs/JOB_CONTRACT.md
CHANGED
|
@@ -8,7 +8,8 @@ this contract. Chat interruption never cancels an engine job.
|
|
|
8
8
|
Mutations use `{schema_version: 1, operation, input, idempotency_key}`.
|
|
9
9
|
Supported operations are `wallet.add` (address, exact tag), `wallet.refresh`
|
|
10
10
|
(wallet address or exact tag), `prices.refresh` (same), `wallet.setTags`
|
|
11
|
-
(wallet, exact tags), `
|
|
11
|
+
(wallet, exact tags), `settings.rpc`, `settings.discovery`, `settings.provider`,
|
|
12
|
+
`job.resume` and `job.cancel` (job_id).
|
|
12
13
|
Read operations are `job.read`, `job.list`, `snapshot.read`, and
|
|
13
14
|
`snapshots.compare`. The portfolio projection retains its existing schema.
|
|
14
15
|
|
|
@@ -21,6 +22,17 @@ the same job without rerunning providers. Resume requeues the same job ID and
|
|
|
21
22
|
increments its attempt on execution. Retain the key until the job is removed
|
|
22
23
|
by a future explicit retention policy. Version mismatches fail closed.
|
|
23
24
|
|
|
25
|
+
`settings.provider` accepts exactly `{provider: "public" | "alchemy", key_env}`.
|
|
26
|
+
The key reference is a bounded environment variable name, never a credential.
|
|
27
|
+
One writer-locked atomic replacement changes RPC mode and discovery together.
|
|
28
|
+
Alchemy updates generated network references while preserving explicit custom
|
|
29
|
+
chain overrides, unrelated chains, explorer choice and public fallback policy.
|
|
30
|
+
A missing local key fails before replacement. Public mode keeps inactive custom
|
|
31
|
+
references for later use. A detected key is not a validated provider or complete
|
|
32
|
+
holdings result. Existing settings.rpc and settings.discovery requests remain
|
|
33
|
+
compatible. The browser waits for terminal settings results; retrying a lost
|
|
34
|
+
result checks the same accepted job instead of submitting another change.
|
|
35
|
+
|
|
24
36
|
## Envelope
|
|
25
37
|
|
|
26
38
|
Each private `jobs/<uuid>.json` records schema_version, job_id, operation,
|
|
@@ -4,6 +4,27 @@ Kira connects the user's installed, unmodified Codex or Claude Code CLI. It does
|
|
|
4
4
|
|
|
5
5
|
The setup flow separates account readiness, model choice, context permission, and confirmation. The conversation composer remains visible. It shows the connected CLI, automatic context scope, response state, cancellation, and a new conversation action. Enter sends; Shift+Enter adds a line; composition events never send.
|
|
6
6
|
|
|
7
|
+
`kira setup` opens the existing Account, Permissions and Ready modal directly
|
|
8
|
+
after the local session and workspace are available. Opening setup does not run
|
|
9
|
+
a model response check, save permissions or start wallet research. Existing
|
|
10
|
+
settings are loaded when setup is reopened. Closing the modal consumes that
|
|
11
|
+
page's setup request, so background polling does not reopen it. Ordinary
|
|
12
|
+
`kira start` keeps the normal workspace entry behavior.
|
|
13
|
+
|
|
14
|
+
The 0.1.5 selector defaults to Use default model. Codex uses a bounded stdio
|
|
15
|
+
app-server handshake and model/list request; it never starts a thread or turn.
|
|
16
|
+
The subprocess has an eight-second metadata deadline and 256 KB output bound.
|
|
17
|
+
Metadata failures leave the default and Advanced identifier entry available.
|
|
18
|
+
Only installed supported CLI versions are queried. Claude uses its documented
|
|
19
|
+
Sonnet, Opus and Haiku aliases. Every chosen model still requires a deliberate
|
|
20
|
+
generic response test. Vendor account and managed policies may restrict access.
|
|
21
|
+
Workspace settings reuses this modal for both providers and all permissions.
|
|
22
|
+
Fresh setup preselects local history; existing false values remain false.
|
|
23
|
+
History permits reopening chats, without extending model memory or scope.
|
|
24
|
+
No wallet context permits general chat and manual wallet management while
|
|
25
|
+
wallet context and research tools remain unavailable. Any effective model or
|
|
26
|
+
permission change starts a fresh conversation.
|
|
27
|
+
|
|
7
28
|
Automatic context is none, one explicitly selected registered wallet, or the whole recorded portfolio. An allowlisted projection preserves exact balances, contract and chain identities, timestamps, unknown values, and coverage gaps. It excludes credentials, RPC endpoints, paths, raw errors, jobs, and provider payloads. User-entered text is also sent to the selected provider. Scope, wallet, provider, or model changes start a new conversation and never replay old messages. Only a bounded current conversation is replayed.
|
|
8
29
|
|
|
9
30
|
Approved wallet context can include validated historical full-balance Mint Club
|
|
@@ -53,7 +74,7 @@ in Activity and also appear in the chat tray. Unanalysed wallets show a sidebar
|
|
|
53
74
|
spinner and open Activity while their first holdings job is active.
|
|
54
75
|
|
|
55
76
|
History is capped at 100 memory sessions and reads up to 200 validated local
|
|
56
|
-
files. Saving remains
|
|
77
|
+
files. Saving is recommended for fresh setup and remains an editable choice. Memory sessions disappear when the process stops.
|
|
57
78
|
A previous session can continue only with exactly the same model and context
|
|
58
79
|
configuration. Reading history does not expand model access. Old saved files
|
|
59
80
|
remain readable. No missing memory-only conversations are reconstructed.
|
|
@@ -65,3 +86,15 @@ The receipt is consumed only on success. This does not enable history retention.
|
|
|
65
86
|
The Kira system voice is concise, composed and practical. It leads with findings
|
|
66
87
|
and preserves evidence, unknown values and signing boundaries. Personality is
|
|
67
88
|
prompt guidance; response quality still depends on the selected model.
|
|
89
|
+
|
|
90
|
+
## 0.1.5 preparation evidence
|
|
91
|
+
|
|
92
|
+
The combined settings and model-selection tests cover catalog failures, stale
|
|
93
|
+
responses, custom identifiers, fresh retention defaults, saved opt-outs,
|
|
94
|
+
atomic provider changes, preference preservation, missing keys, cancellation
|
|
95
|
+
and ambiguous receipts. Desktop 1440 × 900 and mobile 390 × 844 checks used an
|
|
96
|
+
empty disposable workspace. Codex 0.158.0 and Claude Code 2.1.293 completed
|
|
97
|
+
native default-model response checks with no wallet data. The provider save
|
|
98
|
+
used a synthetic local key reference and made no provider research request.
|
|
99
|
+
Real extension approval, personal OWS passphrases and live holdings coverage
|
|
100
|
+
are separate operator acceptance. Published 0.1.4 snapshots are not rewritten.
|
package/docs/RELEASE.md
CHANGED
|
@@ -32,7 +32,7 @@ creation now identifies Open Wallet Standard with its official locally served
|
|
|
32
32
|
logo and explains encrypted local storage and public-account research. The
|
|
33
33
|
OWS integration and wallet-operation permissions are unchanged.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Published **0.1.4** makes incomplete token discovery visible
|
|
36
36
|
before registration and beside wallet holdings, separates disabled discovery
|
|
37
37
|
from missing credentials and provider failures, and offers a connection or
|
|
38
38
|
holdings-refresh action. Registry failures retain bounded redacted examples
|
|
@@ -44,10 +44,21 @@ 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
|
-
|
|
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
|
+
The next candidate is **0.1.6**. It 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 requires review and operator registry publication. It is not yet
|
|
60
|
+
published. The showcase remains a separate deployment. See
|
|
61
|
+
[free RPC behavior](FREE_RPC.md) and [Alchemy setup](ALCHEMY_SETUP.md).
|
|
51
62
|
|
|
52
63
|
The operator published npm **0.1.2** on 2026-10-05. Its registry archive was
|
|
53
64
|
downloaded and matched the reviewed GitHub archive above, including SHA-256,
|
|
@@ -69,8 +80,7 @@ The earlier unpublished 0.1.2 candidate is preserved in the ignored
|
|
|
69
80
|
`dist/preserved-0.1.2-bad8f02/` directory. Use the current `dist/release.json`
|
|
70
81
|
and its matching archive for publication; do not mix manifests from candidates.
|
|
71
82
|
|
|
72
|
-
Keep GitHub v0.1.1, its tag and its released archive immutable. Versions 0.1.2
|
|
73
|
-
and 0.1.3 are also published and immutable. Do not rebuild them from later documentation
|
|
83
|
+
Keep GitHub v0.1.1, its tag and its released archive immutable. Versions 0.1.2, 0.1.3, 0.1.4 and 0.1.5 are also published and immutable. Do not rebuild them from later documentation
|
|
74
84
|
commits. Future package changes need a new version. Release preparation does not
|
|
75
85
|
publish a GitHub release, merge PR 19, promote the website or publish to npm.
|
|
76
86
|
Registry publication remains operator-only. The coding agent never publishes.
|
|
@@ -85,12 +95,12 @@ python3 scripts/prepare-release.py
|
|
|
85
95
|
```
|
|
86
96
|
|
|
87
97
|
`prepare-release.py` scans the package boundary and creates
|
|
88
|
-
`dist/kira-wallet-0.1.
|
|
98
|
+
`dist/kira-wallet-0.1.6.tgz`. The ignored `dist/release.json` records its source
|
|
89
99
|
commit, SHA-256 and member count. It never publishes. After reviewing that
|
|
90
100
|
manifest, the operator's final command from the project root is:
|
|
91
101
|
|
|
92
102
|
```sh
|
|
93
|
-
npm publish ./dist/kira-wallet-0.1.
|
|
103
|
+
npm publish ./dist/kira-wallet-0.1.6.tgz --access public
|
|
94
104
|
```
|
|
95
105
|
|
|
96
106
|
Use the operator's npm account and complete authentication or OTP personally.
|
package/kira_agent.py
CHANGED
|
@@ -251,6 +251,7 @@ class AgentStore:
|
|
|
251
251
|
self.root = Path(root);self.path = self.root/'.kira-agent.json';self.runner=runner;self.detector=detector
|
|
252
252
|
self.lock=threading.RLock();self.turns={};self.active=None;self.epoch=0;self.messages=[];self.conversation=str(uuid.uuid4());self.tested=set();self.config=None;self.workers=[];self.tool_status=None
|
|
253
253
|
self._capabilities=None;self._checked=0
|
|
254
|
+
self._model_lock=threading.Lock();self._model_cache={}
|
|
254
255
|
self.sessions={};self.started_at=datetime.now(timezone.utc).isoformat();self.updated_at=self.started_at
|
|
255
256
|
if self.path.exists():
|
|
256
257
|
try: self.config=config_input(json.loads(self.path.read_text()),self.root)
|
|
@@ -344,6 +345,19 @@ class AgentStore:
|
|
|
344
345
|
self._capabilities=self.detector();self._checked=time.monotonic()
|
|
345
346
|
with self.lock:return {'config':self.config,'providers':self._capabilities,'conversation_id':self.conversation,'messages':self.messages.copy(),'active_turn':self.active,'tool_status':self.tool_status}
|
|
346
347
|
|
|
348
|
+
def models(self, provider, recheck=False):
|
|
349
|
+
if provider not in PROVIDERS:raise JobError('invalid_provider','Choose Codex or Claude.')
|
|
350
|
+
with self._model_lock:
|
|
351
|
+
row=next((row for row in self.status(recheck)['providers'] if row['id']==provider),None)
|
|
352
|
+
if not row or not row['installed'] or not row['supported']:
|
|
353
|
+
return {'models':[], 'note':'Install a supported CLI to load model choices. The default model remains available.'}
|
|
354
|
+
cached=self._model_cache.get(provider)
|
|
355
|
+
if not recheck and cached and time.monotonic()-cached[0]<60:return cached[1]
|
|
356
|
+
from kira_models import catalog
|
|
357
|
+
result=catalog(provider)
|
|
358
|
+
self._model_cache[provider]=(time.monotonic(),result)
|
|
359
|
+
return result
|
|
360
|
+
|
|
347
361
|
def fingerprint(self,config):return hashlib.sha256(json.dumps(config,sort_keys=True).encode()).hexdigest()
|
|
348
362
|
|
|
349
363
|
def stop(self):
|
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.')
|
|
@@ -232,14 +232,14 @@ def main():
|
|
|
232
232
|
if args.command=='config':
|
|
233
233
|
file=Path(args.file).expanduser().resolve()
|
|
234
234
|
if not file.is_file():raise ValueError('Secret environment file does not exist.')
|
|
235
|
-
from
|
|
236
|
-
cfg
|
|
237
|
-
cfg['
|
|
238
|
-
'chains':{str(cid):{'url_env':args.key_env,'alchemy_network':name} for cid,name in ALCHEMY.items()}}
|
|
235
|
+
from kira_config import provider_config
|
|
236
|
+
cfg=provider_config(cfg,'alchemy',args.key_env)
|
|
237
|
+
cfg['secret_env_file']=str(file);cfg['discovery']['explorers']=True
|
|
239
238
|
elif args.command=='discovery':cfg['discovery']={'provider':args.provider,'key_env':args.key_env,'explorers':args.explorers}
|
|
240
239
|
elif args.setting=='public':cfg['rpc']['mode']='public'
|
|
241
240
|
else:
|
|
242
241
|
cfg['rpc'].update(mode='custom')
|
|
242
|
+
if args.priority:cfg['rpc']['priority']=args.priority
|
|
243
243
|
if args.public_fallback is not None:cfg['rpc']['allow_public_fallback']=args.public_fallback
|
|
244
244
|
cfg['rpc']['chains'][str(args.chain)]={'url_env':args.url_env}
|
|
245
245
|
# Validate before replacing the user's working configuration.
|
package/kira_config.py
CHANGED
|
@@ -16,9 +16,22 @@ 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':{}},
|
|
19
|
+
return {'schema_version':1,'rpc':{'mode':'public','allow_public_fallback':True,'priority':'public_first','chains':{}},
|
|
20
20
|
'discovery':{'provider':'none','key_env':'ALCHEMY_API_KEY','explorers':False}}
|
|
21
21
|
|
|
22
|
+
def provider_config(config, provider, key_env):
|
|
23
|
+
"""One settings transition. Preserve explicit fallback and custom overrides."""
|
|
24
|
+
result={**config,'rpc':{**config['rpc'],'chains':{cid:dict(row) for cid,row in config['rpc']['chains'].items()}},
|
|
25
|
+
'discovery':{**config['discovery'],'provider':'alchemy' if provider=='alchemy' else 'none','key_env':key_env}}
|
|
26
|
+
result['rpc']['mode']='custom' if provider=='alchemy' else 'public'
|
|
27
|
+
if provider=='alchemy':
|
|
28
|
+
from wallet import ALCHEMY
|
|
29
|
+
for cid,network in ALCHEMY.items():
|
|
30
|
+
previous=result['rpc']['chains'].get(str(cid))
|
|
31
|
+
if not previous or previous.get('alchemy_network'):
|
|
32
|
+
result['rpc']['chains'][str(cid)]={'url_env':key_env,'alchemy_network':network}
|
|
33
|
+
return result
|
|
34
|
+
|
|
22
35
|
def load_config():
|
|
23
36
|
path=config_path()
|
|
24
37
|
if not path.exists():return default_config()
|
|
@@ -31,7 +44,8 @@ def load_config():
|
|
|
31
44
|
raise ValueError('Invalid RPC configuration.')
|
|
32
45
|
if not isinstance(discovery,dict) or discovery.get('provider') not in ('none','alchemy') or type(discovery.get('explorers',False)) is not bool:
|
|
33
46
|
raise ValueError('Invalid discovery configuration.')
|
|
34
|
-
if
|
|
47
|
+
if rpc.get('priority','public_first') not in ('public_first','custom_first'):raise ValueError('Invalid RPC priority.')
|
|
48
|
+
if set(rpc)-{'mode','allow_public_fallback','priority','chains'} or set(discovery)-{'provider','key_env','explorers'}:raise ValueError('Unknown provider configuration fields.')
|
|
35
49
|
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.')
|
|
36
50
|
for name in [discovery.get('key_env'),*[row.get('url_env') if isinstance(row,dict) else None for row in rpc['chains'].values()]]:
|
|
37
51
|
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.')
|
|
@@ -84,7 +98,8 @@ def endpoints(network,cfg=None):
|
|
|
84
98
|
# New setups default to automatic fallback. Preserve an explicit existing
|
|
85
99
|
# opt-out for operators who require custom providers only.
|
|
86
100
|
if not rpc['allow_public_fallback']:return urls
|
|
87
|
-
|
|
101
|
+
public=network.get('public_rpc') or []
|
|
102
|
+
urls=public+urls if rpc.get('priority','public_first')=='public_first' else urls+public
|
|
88
103
|
return list(dict.fromkeys(urls))
|
|
89
104
|
|
|
90
105
|
def runtime():
|
|
@@ -92,7 +107,7 @@ def runtime():
|
|
|
92
107
|
try: values=secret_values(cfg)
|
|
93
108
|
except ValueError: values={}
|
|
94
109
|
return {'endpoints':{str(n['chain_id']):endpoints(n,cfg) for n in networks},
|
|
95
|
-
'secrets':list(values.values()),'data_root':str(data_root())}
|
|
110
|
+
'secrets':list(values.values()),'data_root':str(data_root()),'health_file':str(data_root()/'cache/rpc-health.json')}
|
|
96
111
|
|
|
97
112
|
if __name__=='__main__':
|
|
98
113
|
# Internal child-process channel only. The user CLI never emits this payload.
|
package/kira_jobs.py
CHANGED
|
@@ -19,7 +19,7 @@ import uuid
|
|
|
19
19
|
|
|
20
20
|
ASSETS = Path(__file__).resolve().parent
|
|
21
21
|
State = Literal['queued', 'running', 'interrupted', 'succeeded', 'partial', 'failed', 'cancelled']
|
|
22
|
-
Operation = Literal['wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery']
|
|
22
|
+
Operation = Literal['wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery','settings.provider']
|
|
23
23
|
TERMINAL = {'succeeded', 'partial', 'failed', 'cancelled', 'interrupted'}
|
|
24
24
|
ADDRESS = re.compile(r'0x[0-9a-fA-F]{40}')
|
|
25
25
|
|
|
@@ -124,10 +124,11 @@ class JobStore:
|
|
|
124
124
|
if not isinstance(job,dict) or type(job.get('schema_version')) is not int or job.get('schema_version') != 1: raise JobError('unsupported_version', 'Unsupported persisted job version.')
|
|
125
125
|
required={'schema_version','job_id','operation','input','state','attempt','sequence','result','previous_result','key_hash','request_hash','created_at','updated_at','cancel_requested','checkpoint','stage','events','errors','chains'}
|
|
126
126
|
optional={'raw_hash','control_receipts','control_raw','provider_configuration','started_at'}
|
|
127
|
-
if required-set(job) or set(job)-required-optional or job['job_id']!=job_id or job['checkpoint']!='snapshots/jobs/'+job_id or not isinstance(job['operation'],str) or job['operation'] not in {'wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery'} or not isinstance(job['state'],str) or job['state'] not in TERMINAL|{'queued','running'} or any(type(job[k]) is not int or job[k]<0 for k in ('attempt','sequence')) or type(job['cancel_requested']) is not bool or not isinstance(job['input'],dict) or any(not isinstance(job[k],list) for k in ('events','errors')) or not isinstance(job['chains'],dict):
|
|
127
|
+
if required-set(job) or set(job)-required-optional or job['job_id']!=job_id or job['checkpoint']!='snapshots/jobs/'+job_id or not isinstance(job['operation'],str) or job['operation'] not in {'wallet.add','wallet.refresh','prices.refresh','wallet.setTags','settings.rpc','settings.discovery','settings.provider'} or not isinstance(job['state'],str) or job['state'] not in TERMINAL|{'queued','running'} or any(type(job[k]) is not int or job[k]<0 for k in ('attempt','sequence')) or type(job['cancel_requested']) is not bool or not isinstance(job['input'],dict) or any(not isinstance(job[k],list) for k in ('events','errors')) or not isinstance(job['chains'],dict):
|
|
128
128
|
raise JobError('invalid_envelope','Persisted job validation failed. Preserve the file for recovery.')
|
|
129
129
|
names={'wallet.add':['address','tag'],'wallet.refresh':['wallet'],'prices.refresh':['wallet'],'wallet.setTags':['wallet','tags'],
|
|
130
|
-
'settings.rpc':['mode','chains','allow_public_fallback'],'settings.discovery':['provider','key_env']}[job['operation']]
|
|
130
|
+
'settings.rpc':['mode','chains','allow_public_fallback'],'settings.discovery':['provider','key_env'],'settings.provider':['provider','key_env']}[job['operation']]
|
|
131
|
+
if job['operation']=='settings.rpc' and 'priority' in job['input']:names=names+['priority']
|
|
131
132
|
fields(job['input'],names)
|
|
132
133
|
wallet=job['input'].get('wallet') or job['input'].get('address')
|
|
133
134
|
if wallet is not None and (not isinstance(wallet,str) or not ADDRESS.fullmatch(wallet)):raise JobError('invalid_envelope','Persisted wallet identity is invalid.')
|
|
@@ -154,8 +155,15 @@ class JobStore:
|
|
|
154
155
|
return matches[0]
|
|
155
156
|
|
|
156
157
|
def normalize(self, operation, value):
|
|
158
|
+
if operation == 'settings.provider':
|
|
159
|
+
fields(value,['provider','key_env'])
|
|
160
|
+
if value['provider'] not in ('public','alchemy') or not isinstance(value['key_env'],str) or not re.fullmatch(r'[A-Z_][A-Z0-9_]{0,99}',value['key_env']):
|
|
161
|
+
raise JobError('invalid_settings','Choose a data provider and a local credential reference.')
|
|
162
|
+
return value.copy()
|
|
157
163
|
if operation == 'settings.rpc':
|
|
158
|
-
fields(value,['mode','chains','allow_public_fallback'])
|
|
164
|
+
fields(value,['mode','chains','allow_public_fallback']+(['priority'] if isinstance(value,dict) and 'priority' in value else []))
|
|
165
|
+
if value.get('priority','public_first') not in ('public_first','custom_first'):
|
|
166
|
+
raise JobError('invalid_settings','Choose a valid RPC priority.')
|
|
159
167
|
if value['mode'] not in ('public','custom') or type(value['allow_public_fallback']) is not bool or not isinstance(value['chains'],list) or len(value['chains'])>30:
|
|
160
168
|
raise JobError('invalid_settings','Choose a valid RPC mode and credential references.')
|
|
161
169
|
available={n['chain_id'] for n in read(ASSETS/'sources/rpc-candidates.json')}
|
|
@@ -166,7 +174,7 @@ class JobStore:
|
|
|
166
174
|
raise JobError('invalid_settings','Use a known chain and a unique environment variable reference.')
|
|
167
175
|
chains[str(chain['chain_id'])]={'url_env':chain['url_env']}
|
|
168
176
|
if value['mode']=='custom' and not chains:raise JobError('invalid_settings','Custom RPC requires at least one endpoint reference.')
|
|
169
|
-
return {'mode':value['mode'],'chains':chains,'allow_public_fallback':value['allow_public_fallback']}
|
|
177
|
+
return {'mode':value['mode'],'chains':chains,'allow_public_fallback':value['allow_public_fallback'],**({'priority':value['priority']} if 'priority' in value else {})}
|
|
170
178
|
if operation == 'settings.discovery':
|
|
171
179
|
fields(value,['provider','key_env'])
|
|
172
180
|
if value['provider'] not in ('none','alchemy') or not isinstance(value['key_env'],str) or not re.fullmatch(r'[A-Z_][A-Z0-9_]{0,99}',value['key_env']):raise JobError('invalid_settings','Use a supported indexer and environment variable reference.')
|
|
@@ -399,11 +407,17 @@ class JobStore:
|
|
|
399
407
|
config=load_config()
|
|
400
408
|
if job['operation']=='settings.rpc':
|
|
401
409
|
updated={**job['input'],'chains':{key:dict(row) for key,row in job['input']['chains'].items()}}
|
|
410
|
+
updated.setdefault('priority',config['rpc'].get('priority','public_first'))
|
|
402
411
|
for key,row in updated['chains'].items():
|
|
403
412
|
previous=config['rpc']['chains'].get(key,{})
|
|
404
413
|
if row['url_env']==previous.get('url_env') and previous.get('alchemy_network'):row['alchemy_network']=previous['alchemy_network']
|
|
405
414
|
config['rpc']=updated
|
|
406
|
-
|
|
415
|
+
elif job['operation']=='settings.discovery':config['discovery']={**job['input'],'explorers':config['discovery'].get('explorers',False)}
|
|
416
|
+
else:
|
|
417
|
+
from kira_config import provider_config,secret_values
|
|
418
|
+
config=provider_config(config,**job['input'])
|
|
419
|
+
if job['input']['provider']=='alchemy' and not secret_values(config).get(job['input']['key_env']):
|
|
420
|
+
raise JobError('connection_key_missing','Kira cannot find the local Alchemy key. Follow the connection guide, then retry. Existing settings are unchanged.')
|
|
407
421
|
atomic(config_path(),config)
|
|
408
422
|
result={'status':'completed','setting':job['operation']};atomic(self.jobs/'results'/(job['job_id']+'.json'),result);return result
|
|
409
423
|
env = {**os.environ, 'KIRA_DATA_DIR': str(self.root), 'KIRA_JOB_ID': job['job_id'], 'KIRA_JOB_SNAPSHOT': job['checkpoint'], 'KIRA_ANALYSIS_FD': str(writer.fileno()), 'PYTHONUNBUFFERED': '1'}
|