┌──────────────────┐ │ struct Models │ ├──────────────────┤ │ ArchonProject │ │ ArchonTask │ │ ChatMessage │ │ TaskEvent │ │ ProviderMetadata │ │ APIError │ └──────────────────┘

Models Reference

Complete Codable model reference for all data types.

: Codable : Identifiable : Hashable ───────────── snake_case ↔ camelCase
Developer Docs Archon iOS · Swift · SwiftUI API v1

Models Reference

Complete Codable model reference for all data types.

Overview

All models in Archon conform to Codable and use a shared JSONDecoder configured with snake_case key decoding strategy. Models are defined in the Models/ directory.

// Shared decoder configuration
extension JSONDecoder {
    static let archonDecoder: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        decoder.dateDecodingStrategy = .iso8601
        return decoder
    }()
}

ArchonProject

struct ArchonProject: Codable, Identifiable, Hashable {
    let id: UUID
    var name: String
    var description: String?
    var createdAt: Date
    var updatedAt: Date
    var taskCount: Int?
    var lastTaskAt: Date?
}

// Database columns (snake_case):
// id, name, description, created_at, updated_at, task_count, last_task_at

ArchonTask

struct ArchonTask: Codable, Identifiable, Hashable {
    let id: UUID
    let projectId: UUID
    var title: String
    var status: TaskStatus
    var errorMessage: String?
    var creditsUsed: Int?
    var modelUsed: String?
    var createdAt: Date
    var updatedAt: Date
    var completedAt: Date?
    var events: [TaskEvent]
}

enum TaskStatus: String, Codable, CaseIterable {
    case created
    case running
    case completed
    case failed
    case cancelled
}

ChatMessage

struct ChatMessage: Codable, Identifiable, Hashable {
    let id: UUID
    let projectId: UUID
    var role: MessageRole
    var content: String
    var createdAt: Date
    var creditsUsed: Int?
}

enum MessageRole: String, Codable {
    case user
    case assistant
    case system
}

TaskEvent

struct TaskEvent: Codable, Identifiable, Hashable {
    let id: UUID
    let taskId: UUID
    let type: EventType
    let message: String
    let stepIndex: Int?
    let metadata: [String: String]?
    let createdAt: Date
}

enum EventType: String, Codable, CaseIterable {
    case stepStarted
    case stepCompleted
    case fileCreated
    case fileModified
    case fileDeleted
    case error
    case info
    case progress
}

ProviderMetadata

struct ProviderMetadata: Codable, Hashable {
    var provider: String          // "anthropic", "openai", "google"
    var model: String             // "claude-sonnet-4-20250514"
    var tokensInput: Int?
    var tokensOutput: Int?
    var latencyMs: Int?
    var fallbackUsed: Bool?
}

APIError

enum APIError: Error, LocalizedError {
    case notAuthenticated
    case notFound
    case conflict
    case validationError(String)
    case serverError(Int)
    case networkError(Error)
    case decodingError(Error)
    case rateLimited(retryAfter: TimeInterval)
    case quotaExceeded

    var errorDescription: String? {
        switch self {
        case .notAuthenticated: return "Session expired. Please sign in."
        case .notFound: return "Resource not found."
        case .conflict: return "Resource already exists."
        case .validationError(let msg): return msg
        case .serverError(let code): return "Server error (\(code))"
        case .networkError: return "Network connection lost."
        case .decodingError: return "Unexpected response format."
        case .rateLimited: return "Too many requests. Please wait."
        case .quotaExceeded: return "Credit limit reached."
        }
    }
}

UserProfile

struct UserProfile: Codable, Identifiable {
    let id: UUID
    var email: String
    var displayName: String?
    var avatarUrl: String?
    var creditsRemaining: Int
    var creditsTotal: Int
    var createdAt: Date
    var subscriptionTier: SubscriptionTier
}

enum SubscriptionTier: String, Codable {
    case free
    case pro
    case team
}

FileNode

struct FileNode: Codable, Identifiable, Hashable {
    let id: UUID
    let projectId: UUID
    var path: String           // "src/components/Button.tsx"
    var fileName: String       // "Button.tsx"
    var content: String?
    var language: String?      // "typescript", "swift", "html"
    var sizeBytes: Int
    var isDirectory: Bool
    var children: [FileNode]?
    var createdAt: Date
    var updatedAt: Date
}

ChatRequest / ChatResponse

struct ChatRequest: Encodable {
    let projectId: UUID
    let message: String
    let conversationId: UUID?
}

struct ChatResponse: Decodable {
    let jobId: UUID
    let status: String
    let creditsUsed: Int?
}

// SSE event payloads (during streaming):
struct SSETextEvent: Decodable {
    let type: String    // "text"
    let content: String
}

struct SSETaskEvent: Decodable {
    let type: String    // "task_start", "task_progress", "task_complete"
    let taskId: UUID
    let step: String?
}

struct SSEDoneEvent: Decodable {
    let type: String    // "done"
    let creditsUsed: Int
}