Configuration
Env and ship.db Database Design
Detailed schema, encryption model, and load/write flow for global_env, agent_env, channel_accounts, and runtime config resolution
Env and ship.db Database Design
This page is the single source of truth for environment-variable storage and ~/.ship/ship.db table design.
1. Goals
- Keep all persistent env values encrypted in
~/.ship/ship.db. - Keep agent runtime isolation strict (no cross-agent env leakage).
- Keep
ship.jsonas binding config, not credential storage. - Keep Console UI and CLI on the same storage model.
2. Data Model Overview
3. Table-by-Table Schema
3.1 global_env
Purpose: console-shared env values.
| Column | Type | Notes |
|---|---|---|
key | TEXT PK | Env key (for example OPENAI_API_KEY) |
value_encrypted | TEXT | AES-GCM encrypted value |
created_at | TEXT | ISO timestamp |
updated_at | TEXT | ISO timestamp |
3.2 agent_env
Purpose: agent-private env values managed in DB.
| Column | Type | Notes |
|---|---|---|
agent_id | TEXT | Agent identity (project root absolute path) |
key | TEXT | Env key |
value_encrypted | TEXT | AES-GCM encrypted value |
created_at | TEXT | ISO timestamp |
updated_at | TEXT | ISO timestamp |
Constraints:
- Primary key:
(agent_id, key) - Index:
agent_id
3.3 channel_accounts
Purpose: central credential vault for chat channels.
| Column | Type | Notes |
|---|---|---|
id | TEXT PK | Bot account id used by ship.json binding |
channel | TEXT | telegram / feishu / qq |
name | TEXT | Display name |
identity | TEXT | Optional human-readable identity |
owner | TEXT | Optional owner info (auto-sync when available) |
creator | TEXT | Optional creator info (auto-sync when available) |
bot_token_encrypted | TEXT | Telegram token (encrypted) |
app_id_encrypted | TEXT | App id (encrypted) |
app_secret_encrypted | TEXT | App secret (encrypted) |
domain | TEXT | Optional domain (mainly Feishu/Lark) |
sandbox | INTEGER | QQ sandbox flag (0/1) |
auth_id | TEXT | Optional master auth id |
created_at | TEXT | ISO timestamp |
updated_at | TEXT | ISO timestamp |
3.4 Existing tables still used
model_providers/models: global model pool.console_secure_settings: non-env secure JSON (currentlyextensions_config).
4. Encryption Boundaries
- Encrypted fields:
global_env.value_encryptedagent_env.value_encryptedchannel_accounts.*_encryptedconsole_secure_settings.value_encrypted- model provider
api_key_encrypted
-
Decryption only happens in runtime memory or API service logic.
-
ship.jsondoes not store plaintext chat credentials.
5. ship.json Binding Model
ship.json stores binding ids, not secrets:
{
"model": {
"primary": "default"
},
"services": {
"chat": {
"channels": {
"qq": {
"enabled": true,
"channelAccountId": "qq-main"
}
}
}
}
}Rules:
model.primarybinds tomodels.id.services.chat.channels.<channel>.channelAccountIdbinds tochannel_accounts.id.- Channel startup requires:
- channel enabled
channelAccountIdexists- required credential fields present in the bound account
6. Runtime Load and Merge Order
7. Where Data Is Written
- Console UI / Channel Accounts page:
- writes
channel_accounts
- Console UI / Model page and model CLI:
- writes
model_providers,models
- Console config (extensions scope) and extension commands:
- writes
console_secure_settings.extensions_config
- Agent channel configure action:
- writes
ship.jsonbinding (channelAccountId,enabled)
8. Operational Notes
<agent>/.envis user-managed and runtime-only overlay.- DB
agent_envis also agent-private; both are merged with.envtaking precedence. - Console shared env is only from
global_env. - For new agents, no credential auto-reuse should happen unless explicitly bound to a channel account.
9. Quick Verification Checklist
channel_accountshas expected rows.- Target agent
ship.jsonchannel haschannelAccountId. - Runtime
chat statusshows:
enabled=trueconfigured=true- channel link status not
config_missing
- New agent without binding should show channel disabled or config missing, not inherited secrets.