// artifact.el — Versioned deliverables subsystem. // // Artifacts are the tangible outputs of Neuron-assisted work: plans, // specifications, architecture docs, reports, design documents. // Unlike raw memories (ephemeral) or knowledge (reference), artifacts are // polished, versioned deliverables that external stakeholders consume. // // WHY explicit versioning? // A plan that gets revised without version tracking looks like a single // authoritative document. With version tracking, you can see when a plan // changed and compare the reasoning at each revision. This is especially // important for architectural decisions that need an audit trail. // // Status machine: // draft → review → approved → archived // // Artifacts are never deleted — only archived. A deleted plan loses its // history. An archived plan retains it. from types import { Artifact, NeuronError, } // ── Public API ──────────────────────────────────────────────────────────────── // draft_artifact — create a new artifact in draft status. // // artifact_types is a list because a document can be multiple things at once: // ["plan", "spec"] for a planning spec, ["report", "analysis"] for an // analysis report. @manager fn draft_artifact( title: String, content: String, artifact_types: [String], project: String, ) -> Result { let id = native_uuid() let now = native_now() // Serialize artifact_types to a comma-joined string for the store. // The Axon response formatter re-splits on display. let artifact_type = artifact_types[0] let artifact = Artifact { id: id, title: title, content: content, artifact_type: artifact_type, status: "draft", project: project, version: 1, created_at: now, updated_at: now, } native_store_artifact(artifact)? native_emit("artifact.drafted", {"id": id, "project": project, "type": artifact_type}) Ok(artifact) } // find_artifacts — list or search artifacts for a project. // // When query is provided, uses semantic search (activate) to find artifacts // by content similarity. When query is empty, returns all project artifacts. @accessor fn find_artifacts(project: String, query: String) -> Result<[Artifact], NeuronError> { if query == "" { let artifacts = native_list_artifacts(project)? return Ok(artifacts) } let results = activate Artifact where "{query} project:{project}" Ok(results) } // retrieve_artifact — fetch a single artifact by ID. @accessor fn retrieve_artifact(id: String) -> Result { let artifact = native_get_artifact(id)? Ok(artifact) } // revise_artifact — update an artifact's content and increment its version. // // Every revision is a distinct event in the graph. The version number is // monotonically increasing — no rollbacks, no overwriting. If you need to // revert, draft a new artifact that references the old version. @manager fn revise_artifact( id: String, content: String, change_summary: String, ) -> Result { let artifact = native_get_artifact(id)? let now = native_now() // Increment version — this is the only place version numbers are assigned. let new_version = artifact.version + 1 let revised = Artifact { id: artifact.id, title: artifact.title, content: content, artifact_type: artifact.artifact_type, status: artifact.status, project: artifact.project, version: new_version, created_at: artifact.created_at, updated_at: now, } native_update_artifact(revised)? native_emit("artifact.revised", { "id": id, "version": "new_version", "summary": change_summary, }) Ok(revised) } // manage_artifact — transition an artifact's status. // // action: "review" | "approve" | "archive" // Valid transitions: // review: draft → review // approve: review → approved // archive: * → archived @manager fn manage_artifact(id: String, action: String) -> Result { let artifact = native_get_artifact(id)? let new_status = if action == "review" { if artifact.status == "draft" { "review" } else { return Err(NeuronError::InvalidInput("can only send a draft artifact for review")) } } else { if action == "approve" { if artifact.status == "review" { "approved" } else { return Err(NeuronError::InvalidInput("can only approve an artifact under review")) } } else { if action == "archive" { "archived" } else { return Err(NeuronError::InvalidInput("unknown artifact action")) } } } let now = native_now() let updated = Artifact { id: artifact.id, title: artifact.title, content: artifact.content, artifact_type: artifact.artifact_type, status: new_status, project: artifact.project, version: artifact.version, created_at: artifact.created_at, updated_at: now, } native_update_artifact(updated)? native_emit("artifact.status_changed", {"id": id, "status": new_status, "action": action}) Ok(updated) }