← Back to Kontasks
gvAgent Linux Secret Service Explained
How gvAgent handles secrets storage on Linux via D-Bus Secret Service
Output
gvAgent Linux Secret Service
How the agent securely stores API keys and credentials on Linux
🔐 Secrets Backend Resolution
The agent uses a fallback chain to find the best available secrets backend:
func New() (SecretsStore, error) { backends := []func() (SecretsStore, error){ // Priority order: tryKeychain, // macOS Keychain (darwin only) tryCredentialMgr, // Windows Credential Manager trySecretService, // Linux secret service via D-Bus ⬅ tryEncryptedFile, // Fallback: encrypted file } for _, try := range backends { store, err := try() if err == nil { return store, nil } } }
📡 Linux Secret Service (D-Bus)
| Protocol: | freedesktop.org Secret Service API |
| Transport: | D-Bus session bus |
| Implementations: | GNOME Keyring KDE Wallet |
| File: | internal/secrets/secretservice_linux.go |
When a user is logged into a GNOME or KDE desktop session, D-Bus is available and secrets are stored in the user's keyring — encrypted and unlocked by the user's login password.
📁 Fallback: Encrypted File
When D-Bus/Secret Service is unavailable (headless servers, Termux, SSH sessions):
| Path: | ~/.local/share/gvagent/secrets.age |
| Encryption: | AES-256-GCM or XChaCha20-Poly1305 |
| Key derivation: | Argon2id (or scrypt) |
| Dir mode: | 0700 |
| File mode: | 0600 |
🛡️ SecretStore Interface
type SecretStore interface { Get(key string) (string, error) Set(key, value string) error Delete(key string) error }
All platform backends implement this interface. Provider API keys (Claude, OpenAI, etc.) are stored via Set() and retrieved via Get().
📊 Platform Comparison
| Platform | Primary Backend | Fallback |
|---|---|---|
| macOS | Keychain | Encrypted file |
| Windows | Credential Manager | Encrypted file |
| Linux (desktop) | Secret Service (D-Bus) | Encrypted file |
| Linux (headless) | (skipped) | Encrypted file |
| Termux | (no D-Bus) | Encrypted file |
What's Next?
Choose an action:
Quick Actions
Original Request
No layout configured
Details
Type
General
Status
Completed
Scope
vibetools
Tags
gvagentsecretslinuxsecurity
Created
6 Jan 2026, 7:53 am
Updated
6 Jan 2026, 7:53 am
Timing
⏱️ 60.4s
0 tools
● TTFE 0%
● Thinking 100%
● Tools 0%
Created By
claude
Raw Data
{
"id": "72f130e8-699f-4189-a242-5960d8ae4d05",
"type": "general",
"status": "completed",
"title": "gvAgent Linux Secret Service Explained",
"description": "How gvAgent handles secrets storage on Linux via D-Bus Secret Service",
"context": {
"output": "<div style=\"background:#1e1e1e;color:#e0e0e0;padding:20px;border-radius:8px;font-family:'Consolas','Monaco',monospace;\">\n<h2 style=\"font-family:sans-serif;color:#fff;margin:0 0 16px 0;\">gvAgent Linux Secret Service</h2>\n<p style=\"color:#9ca3af;margin:0 0 16px 0;\">How the agent securely stores API keys and credentials on Linux</p>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#98c379;margin:0 0 12px 0;\">🔐 Secrets Backend Resolution</h3>\n<p style=\"color:#e0e0e0;margin:0 0 12px 0;\">The agent uses a <strong>fallback chain</strong> to find the best available secrets backend:</p>\n<pre style=\"background:#3d3d3d;padding:12px;border-radius:4px;overflow-x:auto;line-height:1.8;margin:0;\">\n<span style=\"color:#c678dd;\">func</span> <span style=\"color:#61afef;\">New</span>() (SecretsStore, error) {\n backends := []<span style=\"color:#c678dd;\">func</span>() (SecretsStore, error){\n <span style=\"color:#7f848e;\">// Priority order:</span>\n tryKeychain, <span style=\"color:#7f848e;\">// macOS Keychain (darwin only)</span>\n tryCredentialMgr, <span style=\"color:#7f848e;\">// Windows Credential Manager</span>\n <span style=\"color:#98c379;font-weight:bold;\">trySecretService</span>, <span style=\"color:#7f848e;\">// Linux secret service via D-Bus ⬅</span>\n tryEncryptedFile, <span style=\"color:#7f848e;\">// Fallback: encrypted file</span>\n }\n <span style=\"color:#c678dd;\">for</span> _, try := <span style=\"color:#c678dd;\">range</span> backends {\n store, err := try()\n <span style=\"color:#c678dd;\">if</span> err == <span style=\"color:#d19a66;\">nil</span> { <span style=\"color:#c678dd;\">return</span> store, <span style=\"color:#d19a66;\">nil</span> }\n }\n}\n</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#61afef;margin:0 0 12px 0;\">📡 Linux Secret Service (D-Bus)</h3>\n<table style=\"width:100%;border-collapse:collapse;\">\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;width:140px;\">Protocol:</td><td style=\"padding:8px;\"><a href=\"https://specifications.freedesktop.org/secret-service/\" style=\"color:#61afef;\">freedesktop.org Secret Service API</a></td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">Transport:</td><td style=\"padding:8px;\">D-Bus session bus</td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">Implementations:</td><td style=\"padding:8px;\"><span style=\"background:#3b82f6;color:#fff;padding:2px 8px;border-radius:4px;margin-right:6px;\">GNOME Keyring</span> <span style=\"background:#c678dd;color:#fff;padding:2px 8px;border-radius:4px;\">KDE Wallet</span></td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">File:</td><td style=\"padding:8px;\"><code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;\">internal/secrets/secretservice_linux.go</code></td></tr>\n</table>\n<p style=\"color:#9ca3af;margin:12px 0 0 0;font-size:0.9rem;\">When a user is logged into a GNOME or KDE desktop session, D-Bus is available and secrets are stored in the user's keyring — encrypted and unlocked by the user's login password.</p>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#e5c07b;margin:0 0 12px 0;\">📁 Fallback: Encrypted File</h3>\n<p style=\"color:#e0e0e0;margin:0 0 12px 0;\">When D-Bus/Secret Service is unavailable (headless servers, Termux, SSH sessions):</p>\n<table style=\"width:100%;border-collapse:collapse;\">\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;width:140px;\">Path:</td><td style=\"padding:8px;\"><code style=\"background:#3d3d3d;padding:2px 6px;border-radius:3px;\">~/.local/share/gvagent/secrets.age</code></td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">Encryption:</td><td style=\"padding:8px;\">AES-256-GCM or XChaCha20-Poly1305</td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">Key derivation:</td><td style=\"padding:8px;\">Argon2id (or scrypt)</td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">Dir mode:</td><td style=\"padding:8px;\"><code>0700</code></td></tr>\n<tr><td style=\"padding:8px;color:#56b6c2;font-weight:bold;\">File mode:</td><td style=\"padding:8px;\"><code>0600</code></td></tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#c678dd;margin:0 0 12px 0;\">🛡️ SecretStore Interface</h3>\n<pre style=\"background:#3d3d3d;padding:12px;border-radius:4px;overflow-x:auto;line-height:1.6;margin:0;\">\n<span style=\"color:#c678dd;\">type</span> <span style=\"color:#e5c07b;\">SecretStore</span> <span style=\"color:#c678dd;\">interface</span> {\n <span style=\"color:#61afef;\">Get</span>(key <span style=\"color:#56b6c2;\">string</span>) (<span style=\"color:#56b6c2;\">string</span>, <span style=\"color:#56b6c2;\">error</span>)\n <span style=\"color:#61afef;\">Set</span>(key, value <span style=\"color:#56b6c2;\">string</span>) <span style=\"color:#56b6c2;\">error</span>\n <span style=\"color:#61afef;\">Delete</span>(key <span style=\"color:#56b6c2;\">string</span>) <span style=\"color:#56b6c2;\">error</span>\n}\n</pre>\n<p style=\"color:#9ca3af;margin:12px 0 0 0;font-size:0.9rem;\">All platform backends implement this interface. Provider API keys (Claude, OpenAI, etc.) are stored via <code>Set()</code> and retrieved via <code>Get()</code>.</p>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;\">\n<h4 style=\"margin:0 0 8px 0;color:#fff;\">📊 Platform Comparison</h4>\n<table style=\"width:100%;border-collapse:collapse;\">\n<tr style=\"background:#3d3d3d;\"><th style=\"padding:8px;text-align:left;color:#fff;\">Platform</th><th style=\"padding:8px;text-align:left;color:#fff;\">Primary Backend</th><th style=\"padding:8px;text-align:left;color:#fff;\">Fallback</th></tr>\n<tr><td style=\"padding:8px;\">macOS</td><td style=\"padding:8px;\">Keychain</td><td style=\"padding:8px;\">Encrypted file</td></tr>\n<tr><td style=\"padding:8px;\">Windows</td><td style=\"padding:8px;\">Credential Manager</td><td style=\"padding:8px;\">Encrypted file</td></tr>\n<tr style=\"background:#3d4d3d;\"><td style=\"padding:8px;color:#98c379;\">Linux (desktop)</td><td style=\"padding:8px;color:#98c379;\">Secret Service (D-Bus)</td><td style=\"padding:8px;\">Encrypted file</td></tr>\n<tr><td style=\"padding:8px;\">Linux (headless)</td><td style=\"padding:8px;color:#7f848e;\">(skipped)</td><td style=\"padding:8px;\">Encrypted file</td></tr>\n<tr><td style=\"padding:8px;\">Termux</td><td style=\"padding:8px;color:#7f848e;\">(no D-Bus)</td><td style=\"padding:8px;\">Encrypted file</td></tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-top:16px;\">\n<h4 style=\"margin:0 0 8px 0;color:#fff;\">What's Next?</h4>\n<p style=\"color:#9ca3af;margin:0;\">Choose an action:</p>\n</div>\n</div>",
"requestedAt": "2026-01-06T12:15:00Z",
"requestId": "81dba387-e742-4524-bd61-465ee10ce699",
"choices": [
{
"label": "Show security model",
"value": "Show me the full gvAgent security model from gvAgentDesign.md Section 13",
"primary": true
},
{
"label": "Show encrypted file details",
"value": "Explain the encrypted file fallback in more detail - how is the master key derived?"
},
{
"label": "Back to overview",
"value": "Show me the gvAgent documentation coverage summary again"
}
],
"turnTiming": {
"totalMs": 60444,
"ttfeMs": 58,
"thinkingMs": 60386,
"toolExecutionMs": 0,
"toolCallCount": 0,
"thinkingPct": 100,
"toolsPct": 0,
"ttfePct": 0
}
},
"createdBy": "claude",
"createdAt": "2026-01-05T21:53:28.276Z",
"updatedAt": "2026-01-05T21:53:34.515Z",
"requestId": "81dba387-e742-4524-bd61-465ee10ce699",
"scope": "vibetools",
"tags": [
"gvagent",
"secrets",
"linux",
"security"
],
"targetUser": "claude"
}