spb/zyquo-agent Public MIT
The autonomous agent that actually operates your Mac — plans, runs real commands, verifies its own work.
Swift 94.7%
Shell 4.1%
Python 0.7%
Makefile 0.5%
1//2// TaskTemplate.swift3// Zyquo Agent4//5// Author: Simon-Pierre Boucher6// Mail: contact@spboucher.ai7//8// Ready-made agent task templates (Phase 6): a title, category, prompt with9// {{variable}} placeholders, and a suggested safety mode. The built-in10// library ships ≥25 genuinely useful tasks; user templates layer on top11// (TemplateStore). Using a template with variables opens the fill-in sheet.12//1314import Foundation1516/// Template grouping shown in the browser and the command palette.17enum TemplateCategory: String, Codable, CaseIterable, Identifiable {18 case filesAndFolders19 case development20 case automation21 case data22 case systemInfo23 case writing2425 var id: String { rawValue }2627 var displayName: String {28 switch self {29 case .filesAndFolders: return "Files & Folders"30 case .development: return "Development"31 case .automation: return "Automation (AppleScript)"32 case .data: return "Data"33 case .systemInfo: return "System Info"34 case .writing: return "Writing"35 }36 }3738 var symbolName: String {39 switch self {40 case .filesAndFolders: return "folder"41 case .development: return "chevron.left.forwardslash.chevron.right"42 case .automation: return "applescript"43 case .data: return "tablecells"44 case .systemInfo: return "cpu"45 case .writing: return "text.quote"46 }47 }48}4950/// One reusable agent task. `prompt` may contain `{{variable}}` placeholders51/// filled in by the user before the task is created.52struct TaskTemplate: Codable, Identifiable, Hashable {53 var id: UUID = UUID()54 var title: String55 var category: TemplateCategory56 /// SF Symbol shown next to the title (defaults to the category glyph).57 var symbolName: String?58 var prompt: String59 var suggestedSafetyMode: SafetyMode = .guarded60 /// Built-ins are read-only; user templates are editable/deletable.61 var isBuiltIn: Bool = false6263 var displaySymbol: String { symbolName ?? category.symbolName }6465 /// Distinct `{{variable}}` names in declaration order.66 var variables: [String] {67 Self.variables(in: prompt)68 }6970 /// Extracts distinct `{{name}}` placeholders from a prompt.71 static func variables(in prompt: String) -> [String] {72 var names: [String] = []73 var rest = Substring(prompt)74 while let open = rest.range(of: "{{"), let close = rest[open.upperBound...].range(of: "}}") {75 let name = rest[open.upperBound..<close.lowerBound]76 .trimmingCharacters(in: .whitespaces)77 if !name.isEmpty, !names.contains(name) {78 names.append(name)79 }80 rest = rest[close.upperBound...]81 }82 return names83 }8485 /// The prompt with every `{{variable}}` replaced by its filled value.86 func renderedPrompt(values: [String: String]) -> String {87 var rendered = prompt88 for (name, value) in values {89 rendered = rendered.replacingOccurrences(of: "{{\(name)}}", with: value)90 rendered = rendered.replacingOccurrences(of: "{{ \(name) }}", with: value)91 }92 return rendered93 }94}9596// MARK: - Built-in library (≥25 templates)9798enum TaskTemplateLibrary {99 static let builtIn: [TaskTemplate] = [100 // ---- Files & Folders (6) ---------------------------------------101 TaskTemplate(102 title: "Organize my Downloads folder",103 category: .filesAndFolders,104 symbolName: "folder.badge.gearshape",105 prompt: "Look at my Downloads folder (~/Downloads), group the files by type into subfolders (Images, Documents, Archives, Installers, Audio, Video, Other), move them accordingly, and show me a summary table of what you moved. Do not delete anything.",106 isBuiltIn: true107 ),108 TaskTemplate(109 title: "Batch-rename files by pattern",110 category: .filesAndFolders,111 symbolName: "textformat.abc.dottedunderline",112 prompt: "Rename all files in {{folder}} to a consistent kebab-case pattern with a zero-padded numeric suffix ({{prefix}}-01, {{prefix}}-02, …), keeping extensions, and list the before → after mapping.",113 isBuiltIn: true114 ),115 TaskTemplate(116 title: "Find my largest files",117 category: .filesAndFolders,118 prompt: "Find the 20 largest files under {{folder}} (skip hidden files and app bundles), and present them as a table with size, path, and last-modified date. Do not modify anything.",119 isBuiltIn: true120 ),121 TaskTemplate(122 title: "Deduplicate a folder",123 category: .filesAndFolders,124 symbolName: "doc.on.doc",125 prompt: "Scan {{folder}} for duplicate files (same content, compare by checksum). Report every duplicate group with paths and sizes, then move the redundant copies (keep the oldest of each group) into a 'Duplicates' subfolder — never delete outright.",126 isBuiltIn: true127 ),128 TaskTemplate(129 title: "Archive old files",130 category: .filesAndFolders,131 symbolName: "archivebox",132 prompt: "In {{folder}}, find files not modified in the last {{months}} months, move them into an 'Archive-{{months}}mo' subfolder preserving their relative structure, then zip that subfolder and report the space it occupies.",133 isBuiltIn: true134 ),135 TaskTemplate(136 title: "Build a folder structure from a spec",137 category: .filesAndFolders,138 symbolName: "folder.badge.plus",139 prompt: "Create this folder structure in the workspace and put a short README.md in each leaf folder describing its purpose:\n\n{{structure}}",140 isBuiltIn: true141 ),142143 // ---- Development (6) --------------------------------------------144 TaskTemplate(145 title: "Set up a Python project and run the tests",146 category: .development,147 prompt: "Create a small Python project in the workspace with a src/ layout, one example module with two functions, pytest tests for them, then run the tests and report the results.",148 isBuiltIn: true149 ),150 TaskTemplate(151 title: "Scaffold a Node.js CLI tool",152 category: .development,153 symbolName: "terminal",154 prompt: "Scaffold a Node.js command-line tool named {{name}} in the workspace: package.json with a bin entry, a src/index.js implementing {{description}}, and a README. Run it once with --help to verify it works.",155 isBuiltIn: true156 ),157 TaskTemplate(158 title: "Initialize a git repository with hygiene files",159 category: .development,160 symbolName: "arrow.triangle.branch",161 prompt: "Initialize a git repository in the workspace with a sensible .gitignore for {{language}}, a README.md skeleton, an MIT LICENSE with the current year, and make the initial commit. Show the resulting git log.",162 isBuiltIn: true163 ),164 TaskTemplate(165 title: "Explain and fix a failing script",166 category: .development,167 symbolName: "ladybug",168 prompt: "Here is a script that fails. Save it in the workspace, run it, diagnose the failure from the actual output, fix it, re-run to verify, and explain the root cause:\n\n{{script}}",169 isBuiltIn: true170 ),171 TaskTemplate(172 title: "Write a script to automate a chore",173 category: .development,174 symbolName: "wand.and.stars",175 prompt: "Write a well-commented shell script in the workspace that {{chore}}. Test it against sample data you create in the workspace first, show the output, and explain how to use it.",176 isBuiltIn: true177 ),178 TaskTemplate(179 title: "Profile a directory's code statistics",180 category: .development,181 symbolName: "chart.bar",182 prompt: "Analyze the source code under {{folder}}: count files and lines per language/extension, find the 10 longest files, and summarize the project layout in a short report saved as report.md in the workspace.",183 isBuiltIn: true184 ),185186 // ---- Automation (AppleScript) (5) --------------------------------187 TaskTemplate(188 title: "Export my Notes to Markdown",189 category: .automation,190 symbolName: "note.text",191 prompt: "Use AppleScript to read my Apple Notes and export each note in the default folder as a Markdown file in the workspace, named after its title.",192 isBuiltIn: true193 ),194 TaskTemplate(195 title: "Create a reminder",196 category: .automation,197 symbolName: "checklist",198 prompt: "Use AppleScript to create a reminder in the Reminders app titled \"{{title}}\" due {{due}}. Confirm it was created by reading it back.",199 isBuiltIn: true200 ),201 TaskTemplate(202 title: "List today's calendar events",203 category: .automation,204 symbolName: "calendar",205 prompt: "Use AppleScript to read today's events from the Calendar app and present them as a Markdown agenda (time, title, calendar name). Save it as agenda.md in the workspace.",206 isBuiltIn: true207 ),208 TaskTemplate(209 title: "Tidy my Desktop into a dated folder",210 category: .automation,211 symbolName: "menubar.dock.rectangle",212 prompt: "Use Finder automation (AppleScript or shell) to move everything currently on my Desktop into a new folder named 'Desktop {{date}}' inside ~/Documents, then list what was moved.",213 isBuiltIn: true214 ),215 TaskTemplate(216 title: "Draft an email in Mail",217 category: .automation,218 symbolName: "envelope",219 prompt: "Use AppleScript to create a DRAFT (do not send) in Apple Mail addressed to {{recipient}} with subject \"{{subject}}\". Write the body from these points: {{points}}. Leave it open for my review.",220 isBuiltIn: true221 ),222223 // ---- Data (4) -----------------------------------------------------224 TaskTemplate(225 title: "Parse a CSV and summarize it",226 category: .data,227 prompt: "Read the CSV file at {{path}}, describe its columns and row count, compute basic statistics for the numeric columns (min/max/mean), surface anything anomalous, and save the summary as summary.md in the workspace.",228 isBuiltIn: true229 ),230 TaskTemplate(231 title: "Convert JSON to CSV",232 category: .data,233 symbolName: "arrow.left.arrow.right",234 prompt: "Read the JSON file at {{path}}, flatten its records sensibly, write them as a CSV in the workspace, and show me the header plus the first 5 rows.",235 isBuiltIn: true236 ),237 TaskTemplate(238 title: "Aggregate a log file",239 category: .data,240 symbolName: "doc.plaintext",241 prompt: "Analyze the log file at {{path}}: count entries per severity level, extract the 10 most frequent error messages with counts, note the time range covered, and write findings.md in the workspace.",242 isBuiltIn: true243 ),244 TaskTemplate(245 title: "Diff two files and explain the changes",246 category: .data,247 symbolName: "plus.forwardslash.minus",248 prompt: "Compare {{fileA}} and {{fileB}} with diff, then explain the meaningful differences in plain language, grouped by theme, and save the annotated diff in the workspace.",249 isBuiltIn: true250 ),251252 // ---- System Info (4) -----------------------------------------------253 TaskTemplate(254 title: "Storage health report",255 category: .systemInfo,256 symbolName: "internaldrive",257 prompt: "Produce a storage report for this Mac: total/used/free disk space, the 10 largest folders in my home directory (one level deep), and cache folders that look safely cleanable. Report only — do not delete anything.",258 isBuiltIn: true259 ),260 TaskTemplate(261 title: "Snapshot my Mac's configuration",262 category: .systemInfo,263 prompt: "Collect a configuration snapshot: macOS version, hardware model, CPU/RAM, uptime, network interfaces with IPs, and installed developer toolchains (git, node, python3, swift — with versions). Save it as system-snapshot.md in the workspace.",264 isBuiltIn: true265 ),266 TaskTemplate(267 title: "What is using my resources right now?",268 category: .systemInfo,269 symbolName: "gauge.with.needle",270 prompt: "Show the 10 processes using the most CPU and the 10 using the most memory right now, with a one-line interpretation of anything unusual. Read-only — do not kill anything.",271 isBuiltIn: true272 ),273 TaskTemplate(274 title: "Audit my login items and launch agents",275 category: .systemInfo,276 symbolName: "power",277 prompt: "List my user LaunchAgents (~/Library/LaunchAgents) and the system ones, with each plist's program and schedule, and flag anything that looks like abandoned software. Read-only — change nothing.",278 isBuiltIn: true279 ),280281 // ---- Writing (4) ----------------------------------------------------282 TaskTemplate(283 title: "Summarize a document",284 category: .writing,285 prompt: "Read the document at {{path}} and write a structured summary (TL;DR, key points, open questions) as summary.md in the workspace, keeping it under 400 words.",286 isBuiltIn: true287 ),288 TaskTemplate(289 title: "Draft a README for a project",290 category: .writing,291 symbolName: "book",292 prompt: "Inspect the project at {{folder}} (layout, manifest files, entry points) and draft a complete README.md in the workspace: what it is, how to install, how to run, and project structure.",293 isBuiltIn: true294 ),295 TaskTemplate(296 title: "Turn rough notes into a document",297 category: .writing,298 symbolName: "square.and.pencil",299 prompt: "Turn these rough notes into a well-structured Markdown document with headings, saved as {{filename}}.md in the workspace:\n\n{{notes}}",300 isBuiltIn: true301 ),302 TaskTemplate(303 title: "Weekly review from my file activity",304 category: .writing,305 symbolName: "calendar.badge.clock",306 prompt: "Find files under {{folder}} modified in the last 7 days, group them by project/folder, and draft a short weekly review (what moved, what looks stalled) as weekly-review.md in the workspace.",307 isBuiltIn: true308 ),309 ]310}311