Understanding the Candidate Lifecycle for Person Profiles in Distilly

The candidate lifecycle for person profiles in Distilly tracks four core metadata fields—created_at, updated_at, version, and status—which are automatically managed across skill_writer.py, skill_schema.py, and version_manager.py to ensure every persona artifact remains versioned and auditable.

The titanwings/distilly repository treats every person profile as a versioned JSON/YAML artifact. Understanding the candidate lifecycle for person profiles is essential for managing how these persona metadata objects evolve from initial creation through archival.

Core Lifecycle Attributes

Distilly persists four fields inside the lifecycle object of every profile's metadata:

  • created_at: ISO-8601 timestamp set automatically on creation via now_iso().
  • updated_at: ISO-8601 timestamp refreshed each time the profile is modified.
  • version: Human-readable version string (e.g., v1, v2) incremented during updates.
  • status: Logical state of the profile, defaulting to active.

Implementation Across the Codebase

Initial Creation in skill_writer.py

The lifecycle begins when tools/skill_writer.py generates a new persona. The module injects initial timestamps and version information into the metadata:


# tools/skill_writer.py – Initial lifecycle injection

normalized_meta["lifecycle"]["created_at"] = normalized_meta.get("created_at", now_iso())
normalized_meta["lifecycle"]["updated_at"] = normalized_meta["lifecycle"]["created_at"]
normalized_meta["lifecycle"]["version"] = "v1"

Schema Normalization in skill_schema.py

The schema layer ensures backward compatibility by backfilling missing lifecycle values. The tools/skill_schema.py module harmonizes metadata across the artifact tree:


# tools/skill_schema.py – Lifecycle consistency enforcement

lifecycle = meta.setdefault("lifecycle", {})
meta["created_at"] = lifecycle.get("created_at", meta.get("created_at", now_iso()))
meta["updated_at"] = lifecycle.get("updated_at", meta.get("updated_at", meta["created_at"]))
meta["version"] = lifecycle.get("version", meta.get("version", "v1"))
lifecycle.setdefault("status", "active")

Version Management in version_manager.py

When existing profiles are updated or restored, tools/version_manager.py handles version bumping and timestamp refreshing:


# tools/version_manager.py – Version bumping on update

meta["lifecycle"]["version"] = f"{target_version}_restored"
meta["lifecycle"]["updated_at"] = now_iso()

Practical Examples

Creating a New Persona

When you create a profile via the CLI, the lifecycle fields initialize automatically:

distilly new-persona --name "Alice" --output ./skills/alice

This command invokes skill_writer.py, which sets lifecycle.created_at to the current ISO timestamp and initializes version as "v1".

Updating an Existing Profile

Modifications trigger the version manager to increment the version and update the timestamp:

distilly update-persona ./skills/alice --patch changes.md

Internally, this calls version_manager.py to bump lifecycle.version (for example, to "v2") and refresh lifecycle.updated_at.

Inspecting Lifecycle Metadata Programmatically

You can read the lifecycle block directly from the meta file:

import json
from pathlib import Path

meta = json.loads(Path("./skills/alice/meta.json").read_text())
print(meta["lifecycle"])

The output shows the complete audit trail:

{
  "created_at": "2026-09-10T12:34:56Z",
  "updated_at": "2026-09-12T08:21:13Z",
  "version": "v2",
  "status": "active"
}

Summary

  • The candidate lifecycle manages four critical fields—created_at, updated_at, version, and status—stored within the lifecycle object of every persona profile.
  • tools/skill_writer.py initializes timestamps and version strings during the creation phase.
  • tools/skill_schema.py normalizes metadata, backfills missing values, and defaults status to "active".
  • tools/version_manager.py increments version strings and refreshes updated_at timestamps during profile modifications.
  • Profiles transition through logical states via the status field, enabling archival workflows without physical deletion.

Frequently Asked Questions

How does Distilly handle missing lifecycle fields in legacy profiles?

When loading older artifacts, tools/skill_schema.py automatically backfills missing created_at, updated_at, and version values. The schema defaults version to "v1" and timestamps to the current time if no historical data exists, ensuring every profile conforms to the current lifecycle specification.

Can the version string format be customized?

The codebase uses semantic-style strings such as "v1" or "v2_restored" (the latter appended by version_manager.py during restore operations). While the system automatically manages these formats, the underlying implementation in version_manager.py uses standard string formatting, allowing teams to modify conventions if they maintain the string type in the lifecycle object.

What values are valid for the status field?

According to the implementation in tools/skill_schema.py, the status field defaults to "active" when initialized via lifecycle.setdefault("status", "active"). The data structure accepts any string value, enabling custom states like "archived" or "deprecated" to suit specific workflow requirements.

Where is the lifecycle metadata physically stored?

The lifecycle object resides inside the meta.json or meta.yaml file within each persona directory. tools/skill_writer.py creates this file initially, while subsequent updates from tools/version_manager.py modify the lifecycle values in place.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →