# AGENTS.md - Octocode Shared
> **Location**: `packages/octocode-shared/AGENTS.md`
AI agent guidance for the `octocode-shared` package - Shared utilities for credential management, session persistence, and platform detection across Octocode packages.
This file **overrides** the root [`AGENTS.md`](../../AGENTS.md) for work within this package.
---
## Overview
Octocode Shared provides common utilities used by multiple Octocode packages:
- **Credential Management**: Secure token storage with AES-256-GCM encryption
- **Session Persistence**: Session state with deferred writes and usage statistics
- **Platform Detection**: Cross-platform path and environment utilities
- **Keychain Integration**: Native keychain access via `keychain-napi`
**Key Consumers**: `octocode-cli`, `octocode-mcp`
---
## ๐ ๏ธ Commands
All commands run from this package directory (`packages/octocode-shared/`).
| Task | Command | Description |
|------|---------|-------------|
| **Build** | `yarn build` | Lint + compile TypeScript |
| **Build (Dev)** | `yarn build:dev` | Compile without lint |
| **Clean** | `yarn clean` | Remove `dist/` directory |
| **Test** | `yarn test` | Run tests with coverage |
| **Test (Quiet)** | `yarn test:quiet` | Minimal test output |
| **Test (Watch)** | `yarn test:watch` | Watch mode for tests |
| **Lint** | `yarn lint` | ESLint check |
| **Lint (Fix)** | `yarn lint:fix` | Auto-fix linting issues |
| **Typecheck** | `yarn typecheck` | TypeScript type checking |
---
## ๐ Documentation
Technical documentation for the shared utilities:
| Document | Description |
|----------|-------------|
| [`CREDENTIALS_ARCHITECTURE.md`](./docs/CREDENTIALS_ARCHITECTURE.md) | Token storage, encryption, keychain integration, refresh flow |
| [`SESSION_PERSISTENCE.md`](./docs/SESSION_PERSISTENCE.md) | Deferred writes, exit handlers, statistics tracking |
| [`API_REFERENCE.md`](./docs/API_REFERENCE.md) | Complete API documentation for all modules |
---
## ๐ Package Structure
```
src/
โโโ index.ts # Package exports
โ
โโโ credentials/ # ๐ Secure credential storage
โ โโโ index.ts # Credentials module exports
โ โโโ keychain.ts # System keychain wrapper (internal)
โ โโโ storage.ts # AES-256-GCM encrypted storage
โ โโโ types.ts # Credential type definitions
โ
โโโ platform/ # ๐ฅ๏ธ Platform utilities
โ โโโ index.ts # Platform module exports
โ โโโ platform.ts # OS detection & paths
โ
โโโ session/ # ๐ Session persistence
โโโ index.ts # Session module exports
โโโ storage.ts # Session storage with deferred writes
โโโ types.ts # Session type definitions
```
### Tests Structure
```
tests/
โโโ credentials/
โ โโโ keychain.test.ts # Keychain integration tests
โ โโโ storage.test.ts # Credential storage tests
โโโ platform/
โ โโโ platform.test.ts # Platform detection tests
โโโ session/
โโโ storage.test.ts # Session storage tests
```
---
## ๐ฆ Module Exports
The package provides four entry points:
```typescript
// Main entry - all exports
import { ... } from 'octocode-shared';
// Credentials only
import { ... } from 'octocode-shared/credentials';
// Platform only
import { ... } from 'octocode-shared/platform';
// Session only
import { ... } from 'octocode-shared/session';
```
### Credentials Module
| Export | Type | Purpose |
|--------|------|---------|
| `storeCredentials` | Function | Store encrypted credentials |
| `getCredentials` | Function | Retrieve credentials (async, cached) |
| `getCredentialsSync` | Function | Retrieve credentials (sync, file only) |
| `deleteCredentials` | Function | Remove stored credentials |
| `getToken` | Function | Get token for a host (async) |
| `getTokenSync` | Function | Get token for a host (sync) |
| `getTokenWithRefresh` | Function | Get token with auto-refresh (recommended) |
| `resolveToken` | Function | Resolve token from env/storage |
| `resolveTokenWithRefresh` | Function | Resolve with auto-refresh |
| `resolveTokenFull` | Function | Full resolution with gh CLI fallback |
| `refreshAuthToken` | Function | Manually refresh an expired token |
| `updateToken` | Function | Update stored token |
| `invalidateCredentialsCache` | Function | Invalidate cached credentials |
| `listStoredHosts` | Function | List all stored hosts |
| `hasCredentials` | Function | Check if credentials exist |
| `isTokenExpired` | Function | Check token expiration |
| `isRefreshTokenExpired` | Function | Check refresh token expiration |
| `initializeSecureStorage` | Function | Initialize keychain-backed storage |
| `isSecureStorageAvailable` | Function | Check if secure storage works |
| `getTokenFromEnv` | Function | Get token from environment |
| `hasEnvToken` | Function | Check for env token |
| `OAuthToken` | Type | OAuth token structure |
| `StoredCredentials` | Type | Credential data structure |
| `TokenSource` | Type | Token origin (env/storage) |
| `GetCredentialsOptions` | Type | Options for getCredentials |
### Platform Module
| Export | Type | Purpose |
|--------|------|---------|
| `getPlatform()` | Function | Get current OS (`darwin`, `win32`, `linux`) |
| `getConfigPath()` | Function | Platform-specific config directory |
| `isWindows()` | Function | Windows detection |
| `isMacOS()` | Function | macOS detection |
| `isLinux()` | Function | Linux detection |
### Session Module
| Export | Type | Purpose |
|--------|------|---------|
| `readSession` | Function | Read current session from cache/disk |
| `writeSession` | Function | Write session (deferred to disk) |
| `getOrCreateSession` | Function | Get existing or create new session |
| `getSessionId` | Function | Get current session ID |
| `deleteSession` | Function | Delete session file |
| `flushSession` | Function | Flush pending writes to disk |
| `flushSessionSync` | Function | Sync flush for exit handlers |
| `updateSessionStats` | Function | Update session statistics |
| `incrementToolCalls` | Function | Increment tool call counter |
| `incrementPromptCalls` | Function | Increment prompt call counter |
| `incrementErrors` | Function | Increment error counter |
| `incrementRateLimits` | Function | Increment rate limit counter |
| `resetSessionStats` | Function | Reset all statistics |
| `SESSION_FILE` | Constant | Path to session file |
| `PersistedSession` | Type | Session data structure |
| `SessionStats` | Type | Usage statistics structure |
| `SessionUpdateResult` | Type | Update result type |
| `SessionOptions` | Type | Session creation options |
---
## ๐ Credential Storage Architecture
### Encryption Details
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CREDENTIAL STORAGE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Token โ AES-256-GCM Encryption โ Base64 โ File Storage โ
โ โ
โ Encryption Key: โ
โ โโโ Stored in system keychain (via keychain-napi) โ
โ โโโ Fallback: File-based key storage โ
โ โ
โ Storage Location: โ
โ โโโ ~/.octocode/credentials.json โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### Security Features
- **AES-256-GCM**: Authenticated encryption with associated data
- **Random IV**: Unique initialization vector per encryption
- **Keychain Integration**: Native OS keychain for encryption key
- **Secure Fallback**: File-based key when keychain unavailable
- **Token Resolution**: Automatic env โ storage โ gh CLI fallback chain
- **Auto-Refresh**: Octocode tokens refreshed automatically when expired (via `@octokit/oauth-methods`)
- **In-Memory Cache**: 5-minute TTL with automatic invalidation on credential updates
---
## ๐ Session Storage Architecture
### Session Persistence
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SESSION STORAGE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ In-Memory Cache โโ Deferred Writes โ File Storage โ
โ โ
โ Write Strategy: โ
โ โโโ Writes are cached in memory โ
โ โโโ Flushed to disk on timer or explicit flush โ
โ โโโ Sync flush on process exit (SIGINT, SIGTERM) โ
โ โ
โ Storage Location: โ
โ โโโ ~/.octocode/session.json โ
โ โ
โ Data Tracked: โ
โ โโโ sessionId, createdAt, lastActiveAt โ
โ โโโ stats: toolCalls, promptCalls, errors, rateLimits โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### Session Features
- **Deferred Writes**: Batches writes for performance
- **In-Memory Caching**: Fast reads from memory
- **Exit Handlers**: Automatic flush on process exit
- **Statistics Tracking**: Tool calls, prompts, errors, rate limits
- **Atomic Counters**: Thread-safe stat increments
---
## ๐ฆ Package Guidelines
These are the core principles for this shared package:
1. **Minimal Dependencies**: Only `keychain-napi` for keychain access.
2. **Cross-Platform**: Must work on macOS, Linux, and Windows.
3. **Type-Safe Exports**: Full TypeScript types with strict mode.
4. **Security First**: All credential operations use encryption.
5. **Performance**: Session writes are deferred for efficiency.
6. **Minimal API Surface**: Export only what's needed by consumers.
---
## ๐๏ธ Architecture Patterns
### Token Resolution Flow
```
resolveTokenFull(options)
โ
getTokenFromEnv() โ Checked first (highest priority, NO REFRESH)
โโโ 1. Check OCTOCODE_TOKEN
โโโ 2. Check GH_TOKEN
โโโ 3. Check GITHUB_TOKEN
โโโ Return { token, source: 'env:*' } if found (user manages these)
โ
getTokenWithRefresh(host) โ ONLY OCTOCODE TOKENS ARE REFRESHED
โโโ Read from in-memory cache (5-min TTL)
โโโ Fallback to keychain or encrypted storage
โโโ Auto-refresh if token expired (using @octokit/oauth-methods)
โโโ Return { token, source: 'keychain'|'file' } if found
โ
getGhCliToken(host) โ Fallback (NO REFRESH - gh CLI manages its own tokens)
โโโ Return { token, source: 'gh-cli' } if found
โ
Return result or null
```
### Token Refresh Policy
| Token Source | Auto-Refresh? | Reason |
|--------------|---------------|--------|
| **Env vars** (`OCTOCODE_TOKEN`, `GH_TOKEN`, `GITHUB_TOKEN`) | โ No | User-managed tokens |
| **Octocode credentials** (keychain/file) | โ
If supported | GitHub App tokens only (see below) |
| **gh CLI token** | โ No | gh CLI handles its own token refresh |
**Token Type Support:**
| Token Type | Expires? | Refresh Token? | Auto-Refresh? |
|------------|----------|----------------|---------------|
| **GitHub App user tokens** | โ
8 hours | โ
Yes | โ
Yes |
| **OAuth App tokens** (classic) | โ Never | โ No | โ N/A |
**Note:** Only tokens with a `refreshToken` field are auto-refreshed. OAuth App tokens never expire and don't need refresh. Octocode uses a GitHub App, so tokens from `octocode login` support auto-refresh.
### Credentials Caching
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ IN-MEMORY CREDENTIALS CACHE โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Cache TTL: 5 minutes (matches token expiry buffer) โ
โ โ
โ Cache Invalidation: โ
โ โโโ storeCredentials() โ invalidates hostname โ
โ โโโ deleteCredentials() โ invalidates hostname โ
โ โโโ updateToken() โ calls storeCredentials() โ
โ โโโ refreshAuthToken() โ calls updateToken() โ
โ โ
โ Bypass Cache: โ
โ โโโ getCredentials(host, { bypassCache: true }) โ
โ โ
โ Manual Invalidation: โ
โ โโโ invalidateCredentialsCache(hostname?) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### Session Write Flow
```
writeSession(session)
โ
cachedSession = session
isDirty = true
โ
registerExitHandlers() (once)
โโโ SIGINT โ flushSessionSync()
โโโ SIGTERM โ flushSessionSync()
โโโ beforeExit โ flushSessionSync()
โ
startFlushTimer()
โโโ setTimeout โ flushSession() โ writeSessionToDisk()
```
### Key Management
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ KEY MANAGEMENT โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Primary: System Keychain (keychain-napi) โ
โ โโโ Service: "octocode" โ
โ โโโ Account: "encryption-key" โ
โ โ
โ Fallback: File-Based Key โ
โ โโโ Location: ~/.octocode/.key โ
โ โโโ Used when keychain unavailable โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
---
## ๐ก๏ธ Safety & Permissions
### Package-Level Access
| Path | Access | Description |
|------|--------|-------------|
| `src/` | โ
FULL | Source code |
| `tests/` | โ
FULL | Test files |
| `*.json`, `*.config.*` | โ ๏ธ ASK | Package configs |
| `dist/`, `coverage/`, `node_modules/` | โ NEVER | Generated files |
### Protected Files
- **Never Modify**: `dist/`, `coverage/`, `node_modules/`
- **Ask Before Modifying**: `package.json`, `tsconfig.json`, `vitest.config.ts`
### Security Considerations
- **Key Isolation**: Encryption keys never leave the system keychain
- **No Plaintext Storage**: Tokens are always encrypted at rest
- **Env Variable Priority**: Environment tokens take precedence
- **Deferred Writes**: Session data is flushed safely on exit
---
## ๐งช Testing Protocol
### Requirements
- **Coverage**: 90% required (Statements, Branches, Functions, Lines)
- **Framework**: Vitest with v8 coverage
### Test Categories
| Category | Path | Purpose |
|----------|------|---------|
| Unit | `tests/credentials/storage.test.ts` | Encryption/decryption, token management |
| Unit | `tests/credentials/keychain.test.ts` | Keychain integration |
| Unit | `tests/platform/platform.test.ts` | OS detection, path resolution |
| Unit | `tests/session/storage.test.ts` | Session persistence, stats, flushing |
### Running Tests
```bash
yarn test # Full test with coverage
yarn test:watch # Watch mode
yarn test:quiet # Minimal output
```
---
## ๐ Development Notes
### Adding New Modules
1. Create module directory under `src/`
2. Add `index.ts` with exports
3. Update `src/index.ts` to re-export
4. Add export path in `package.json` exports field
5. Create corresponding test file
### Dependencies
| Dependency | Purpose |
|------------|---------|
| `keychain-napi` | Native keychain access |
| `@octokit/oauth-methods` | GitHub OAuth token refresh |
| `@octokit/request` | HTTP requests to GitHub API |
### Build Output
```
dist/
โโโ index.js # Main entry
โโโ index.d.ts # Type declarations
โโโ credentials/ # Credentials module
โ โโโ index.js
โ โโโ index.d.ts
โ โโโ keychain.js # Internal keychain wrapper
โ โโโ storage.js
โ โโโ types.d.ts
โโโ platform/ # Platform module
โ โโโ index.js
โ โโโ index.d.ts
โ โโโ platform.js
โโโ session/ # Session module
โโโ index.js
โโโ index.d.ts
โโโ storage.js
โโโ types.d.ts
```