Monorepo for Aesthetic.Computer
aesthetic.computer
Keeps TUI Admin Interface#
A terminal-based UI for managing Keeps NFT contracts across Tezos networks.
Overview#
The Keeps TUI will provide a single command-line interface to:
- Browse and manage multiple Keeps contracts (mainnet + ghostnet)
- Switch between wallet identities (rolodex)
- Perform admin operations on contracts
- View token holdings and minting activity
Architecture#
┌─────────────────────────────────────────────────────────────┐
│ keeps-tui.mjs │
│ (Entry point - imports from keeps.mjs + vault loader) │
├─────────────────────────────────────────────────────────────┤
│ Views: │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐│
│ │ Contracts │ │ Wallet │ │ Token Browser ││
│ │ Browser │ │ Rolodex │ │ (list/search tokens) ││
│ └─────────────┘ └─────────────┘ └─────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ Services: │
│ • TzKT API (read contract state, tokens, holders) │
│ • Taquito (write operations with vault keys) │
│ • Beacon SDK (optional - for external wallet signing) │
└─────────────────────────────────────────────────────────────┘
Wallet Rolodex#
The TUI maintains a rolodex of wallet identities. Private keys stay in vault only.
Wallet Sources#
| Wallet | Address | Source | Role |
|---|---|---|---|
| staging | tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt |
vault/tezos/staging/.env |
Testing |
| kidlisp | tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt |
vault/tezos/kidlisp/.env |
Production |
| aesthetic | tz1gkf8EexComFBJvjtT1zdsisdah791KwBE |
Beacon (external wallet) | Treasury |
| custom | (user specified) | Runtime input / Beacon | Ad-hoc |
Key Loading Strategy#
// Vault loader - NEVER exposes keys outside this module
async function loadWalletFromVault(walletId) {
const envPath = `${VAULT_PATH}/tezos/${walletId}/.env`;
// Returns a signing function, NOT the raw key
return {
address: pubKeyHash,
sign: async (payload) => signWithKey(privateKey, payload),
source: 'vault'
};
}
// For external wallets, use Beacon
async function loadExternalWallet() {
const wallet = new BeaconWallet({ name: 'Keeps TUI' });
await wallet.requestPermissions({ network: { type: NetworkType.MAINNET } });
return {
address: await wallet.getPKH(),
sign: (payload) => wallet.sign(payload),
source: 'beacon'
};
}
Contract Registry#
The TUI tracks known contracts across networks:
const CONTRACTS = {
mainnet: {
staging: {
address: 'KT1EcsqR69BHekYF5mDQquxrvNg5HhPFx6NM',
admin: 'tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt',
label: 'Mainnet Staging',
deployed: '2025-01-XX'
},
production: {
address: null, // TBD
admin: 'tz1gkf8EexComFBJvjtT1zdsisdah791KwBE',
label: 'Mainnet Production',
deployed: null
}
},
ghostnet: {
testing: {
address: 'KT1StXrQNvRd9dNPpHdCGEstcGiBV6neq79K',
admin: 'tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt',
label: 'Ghostnet Testing',
deployed: '2025-01-XX'
}
}
};
TUI Screens#
1. Main Menu#
╔══════════════════════════════════════════════════════════╗
║ KEEPS CONTRACT ADMIN TUI ║
╠══════════════════════════════════════════════════════════╣
║ ║
║ Active Wallet: staging (tz1dfo...4Gzt) ║
║ Network: mainnet ║
║ ║
║ [C] Contracts - Browse & manage contracts ║
║ [W] Wallets - Switch wallet identity ║
║ [T] Tokens - Browse minted tokens ║
║ [M] Mint - Mint a new Keep ║
║ [S] Settings - Configure networks/RPCs ║
║ [Q] Quit ║
║ ║
╚══════════════════════════════════════════════════════════╝
2. Contract Browser#
╔══════════════════════════════════════════════════════════╗
║ CONTRACTS (mainnet) ║
╠══════════════════════════════════════════════════════════╣
║ ║
║ → [1] KT1Ecs...79K STAGING 0 tokens $cow minted ║
║ [2] KT1Abc...123 PRODUCTION -- tokens (not active) ║
║ ║
║ ─────────────────────────────────────────────────────── ║
║ GHOSTNET: ║
║ [3] KT1Stx...q79K TESTING 5 tokens ║
║ ║
║ [Enter] View contract [A] Admin ops [D] Deploy new ║
║ [N] Switch network [B] Back ║
╚══════════════════════════════════════════════════════════╝
3. Contract Detail View#
╔══════════════════════════════════════════════════════════╗
║ KT1EcsqR69BHekYF5mDQquxrvNg5HhPFx6NM ║
║ Mainnet Staging ║
╠══════════════════════════════════════════════════════════╣
║ ║
║ Admin: tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt ║
║ Minter: tz1dfoQDuxjwSgxdqJnisyKUxDHweade4Gzt ║
║ Tokens: 1 ║
║ Balance: 0.05 ꜩ ║
║ ║
║ TOKEN LIST: ║
║ #0 $cow 1 minted holder: tz1gkf...BHE ║
║ ║
║ ─────────────────────────────────────────────────────── ║
║ ADMIN OPERATIONS (requires admin wallet): ║
║ [1] set_metadata [2] update_minter [3] update_admin ║
║ [4] Toggle pause [5] Withdraw balance ║
║ ║
║ [O] Open on objkt [T] Open on TzKT [B] Back ║
╚══════════════════════════════════════════════════════════╝
4. Wallet Rolodex#
╔══════════════════════════════════════════════════════════╗
║ WALLET ROLODEX ║
╠══════════════════════════════════════════════════════════╣
║ ║
║ → [1] staging tz1dfo...Gzt (vault) 0.95 ꜩ ║
║ [2] kidlisp tz1dfo...Gzt (vault) 0.00 ꜩ ║
║ [3] aesthetic tz1gkf...BHE (beacon) -- ║
║ [4] + Add custom wallet ║
║ ║
║ ─────────────────────────────────────────────────────── ║
║ CURRENT: staging ║
║ Can sign: ✓ (vault key loaded) ║
║ ║
║ [Enter] Switch to wallet [B] Back ║
╚══════════════════════════════════════════════════════════╝
CLI Commands#
The TUI also supports direct CLI commands for scripting:
# List contracts
node keeps-tui.mjs contracts --network mainnet
# Switch wallet
node keeps-tui.mjs wallet use staging
# Mint a token
node keeps-tui.mjs mint --name '$butterfly' --wallet staging --network mainnet
# View token
node keeps-tui.mjs token 0 --contract KT1Ecs...
# Admin operations
node keeps-tui.mjs admin set-minter --address tz1abc... --contract KT1Ecs...
node keeps-tui.mjs admin set-metadata --uri ipfs://... --contract KT1Ecs...
Security Model#
Critical Rules#
-
Private keys NEVER leave the vault
- Keys are loaded into memory only during signing
- No key export or display functions
- All signing happens through wrapper functions
-
Vault structure
aesthetic-computer-vault/ └── tezos/ ├── staging/.env # TEZOS_PRIVATE_KEY=edsk... ├── kidlisp/.env # TEZOS_PRIVATE_KEY=edsk... └── wallets.json # Address registry (no keys) -
External wallets via Beacon
- For wallets where vault key isn't available
- Requires manual approval in wallet app
- Used for
aesthetic.tez(Jeffrey's main wallet)
-
Audit logging
- All admin operations logged with timestamp
- Logs stored in vault (not repo)
- Includes: operation, wallet, contract, result
Implementation Phases#
Phase 1: Read-Only Browser#
- Contract list view
- Token browser
- TzKT integration
- Basic TUI framework (blessed or ink)
Phase 2: Wallet Management#
- Vault key loading
- Wallet rolodex UI
- Balance display
- Beacon SDK integration
Phase 3: Admin Operations#
- Mint via TUI
- set_metadata
- update_minter / update_admin
- Pause/unpause
Phase 4: Deployment#
- Deploy new contract from TUI
- Contract comparison (diff storage/code)
- Migration tools
Dependencies#
{
"dependencies": {
"blessed": "^0.1.81", // Terminal UI
"@taquito/taquito": "^19", // Tezos operations
"@airgap/beacon-sdk": "^4", // External wallet connection
"dotenv": "^16" // Vault env loading
}
}
File Location#
tezos/
├── keeps.mjs # Existing CLI (mint, deploy, etc.)
├── keeps-tui.mjs # NEW: Interactive TUI entry point
├── keeps-vault.mjs # NEW: Secure vault key loader
├── keeps-contracts.mjs # NEW: Contract registry
└── KEEPS-TUI-PLAN.md # This document
Notes#
- Start with Phase 1 (read-only) to validate the TUI framework choice
- Consider using
ink(React for CLI) if blessed feels dated - The existing
keeps.mjscommands will be wrapped, not replaced - All destructive operations require confirmation prompt