Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions archaeology/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""JSON API for dev-archaeology strategic insights.

Lightweight API that serves strategic analysis data to The-Factory
and other consumers. Stdlib-only — no Flask/FastAPI dependency.
Lightweight API that serves strategic analysis data to external consumers.
Stdlib-only — no Flask/FastAPI dependency.

Endpoints:
GET /api/health — System status
Expand Down
6 changes: 3 additions & 3 deletions archaeology/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@ def multi_project_dashboard(output_dir, top_n, year, verbose):


@main.command("fetch-github")
@click.option("--owner", default="Pastorsimon1798", help="GitHub username/org")
@click.option("--owner", default=os.environ.get("ARCHAEOLOGY_GITHUB_OWNER", ""), help="GitHub username/org")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require an owner before calling gh

When ARCHAEOLOGY_GITHUB_OWNER is unset and the user runs archaeology fetch-github without --owner, this default becomes "", but the fetcher still passes it as a positional owner to gh repo list rather than omitting the optional argument. The GitHub CLI manual documents the syntax as gh repo list [<owner>], so defaulting to an explicit empty string can make the default command fail or fetch no repos instead of either using the authenticated user/default behavior or giving an actionable error; validate this value or omit the positional argument when it is blank.

Useful? React with 👍 / 👎.

@click.option("--output", "output_path", default="global/data/github-repos.json", help="Output JSON path")
def fetch_github(owner, output_path):
"""Fetch repo metadata from GitHub API for all repos (no cloning)."""
Expand Down Expand Up @@ -1221,7 +1221,7 @@ def serve(port, no_open):
mined_names = {p["name"].lower().replace("-", "").replace("_", "") for p in projects}
api_repos = [r for r in api_repos if r["name"].lower().replace("-", "").replace("_", "") not in mined_names]
print(f" After dedup: {len(api_repos)} API-only repos")
owner_labels = {"Pastorsimon1798": "Pastorsimon1798 (Personal)", "KyaniteLabs": "KyaniteLabs (Org)"}
owner_labels = {} # populated from ARCHAEOLOGY_GITHUB_OWNER env or left empty
api_section_html = generate_global_section(api_repos, owner_labels) if api_repos else ""

dashboard_html = generate_master_dashboard(projects, api_section_html=api_section_html, api_repos=api_repos)
Expand Down Expand Up @@ -1362,7 +1362,7 @@ def publish_static(output_dir):
api_repos = load_api_repos(global_data_dir) if global_data_dir.exists() else []
mined_names = {p["name"].lower().replace("-", "").replace("_", "") for p in projects}
api_repos = [r for r in api_repos if r["name"].lower().replace("-", "").replace("_", "") not in mined_names]
owner_labels = {"Pastorsimon1798": "Pastorsimon1798 (Personal)", "KyaniteLabs": "KyaniteLabs (Org)"}
owner_labels = {} # populated from ARCHAEOLOGY_GITHUB_OWNER env or left empty
api_section_html = generate_global_section(api_repos, owner_labels) if api_repos else ""

dashboard_html = generate_master_dashboard(projects, api_section_html=api_section_html, api_repos=api_repos)
Expand Down
4 changes: 2 additions & 2 deletions archaeology/db/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ def get_eras(db_path: str) -> list[dict]:

Older archaeology databases do not have a start_date column; they usually
expose id and/or dates instead. Prefer start_date when available and fall
back to stable available columns so query helpers do not break on the main
Liminal case study.
back to stable available columns so query helpers do not break on
databases with varying schema versions.
"""
conn = get_connection(db_path)
try:
Expand Down
9 changes: 5 additions & 4 deletions archaeology/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,17 @@ def export_public_case_study(root: str | Path = ".", output_dir: str | Path = "p
(output / "README.md").write_text(
"# Dev-Archaeology Public Case Study\n\n"
"This is a sanitized, publishable demo generated from invented fixture data. "
"It exists to show what Dev-Archaeology produces without exposing Liminal's private evidence archive.\n\n"
"It exists to show what Dev-Archaeology produces using invented fixture data only — "
"no private evidence archives, no personal telemetry.\n\n"
"## Open the case study\n\n"
"```text\npublic-case-study/index.html\n```\n\n"
"## Regenerate locally\n\n"
"```bash\narchaeology public-case-study --output public-case-study\n```\n\n"
"## Data safety\n\n"
"The files in `public-case-study/data/` are invented fixture data only:\n\n"
"- no raw Liminal sessions\n"
"- no YouTube export\n"
"- no resume/profile data\n"
"- no raw session exports\n"
"- no personal watch history\n"
"- no resume or profile data\n"
"- no personal telemetry\n",
encoding="utf-8",
)
Expand Down
19 changes: 9 additions & 10 deletions archaeology/visualization/agent_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,11 @@ def parse_abbreviated_date(date_str: str) -> datetime:
# Try parsing from git log format
return datetime.strptime(date_str.split()[0], "%Y-%m-%d")

# Normalize agent names - treat Simon variants as "Simon"
def normalize_author(author: str) -> str:
"""Normalize author names to canonical agent names."""
author_lower = author.lower()
if "simon" in author_lower:
return "Simon"
elif author_lower == "claude":
ai_agents = {"claude", "kai", "cursor", "kimicode", "codex"}
if "claude" in author_lower:
return "Claude"
elif author_lower == "kai":
return "Kai"
Expand All @@ -138,7 +136,8 @@ def normalize_author(author: str) -> str:
elif author_lower == "demo-project":
return "demo-project"
else:
return author
# Any non-AI author is labeled "Human" — no personal names in framework output
return "Human"

# Group commits by agent and era
agent_stats: Dict[str, Dict[str, Any]] = {}
Expand Down Expand Up @@ -306,7 +305,7 @@ def generate_benchmark_html(benchmark_data: Dict[str, Any], project_name: str) -
--unknown: #495057;
--kimicode: #a78bfa;
--codex: #60a5fa;
--simon: #fbbf24;
--human: #fbbf24;
}

/* ── Layout ── */
Expand Down Expand Up @@ -505,7 +504,7 @@ def generate_benchmark_html(benchmark_data: Dict[str, Any], project_name: str) -
kai: s.getPropertyValue('--kai').trim(),
cursor: s.getPropertyValue('--cursor').trim(),
claude: s.getPropertyValue('--claude').trim(),
simon: s.getPropertyValue('--simon').trim(),
human: s.getPropertyValue('--human').trim(),
kimicode: s.getPropertyValue('--kimicode').trim(),
codex: s.getPropertyValue('--codex').trim(),
unknown: s.getPropertyValue('--unknown').trim(),
Expand All @@ -516,13 +515,13 @@ def generate_benchmark_html(benchmark_data: Dict[str, Any], project_name: str) -
function getAgentColor(name) {{
const colors = getThemeColors();
const colorMap = {{
'Simon': colors.simon || colors.accent,
'Human': colors.human || colors.accent,
'Claude': colors.claude || colors.secondary,
'Kai': colors.kai || colors.text,
'Cursor': colors.cursor || colors.text2,
'KimiCode': colors.kimicode || colors.accent,
'Codex': colors.codex || colors.secondary,
'Liminal': colors.text,
'demo-project': colors.text,
'Unknown': colors.unknown || colors.muted
}};
return colorMap[name] || colorMap['Unknown'];
Expand Down Expand Up @@ -709,7 +708,7 @@ def generate_benchmark_html(benchmark_data: Dict[str, Any], project_name: str) -
// Rework rate with color coding
const reworkCell = row.append('td').classed('mono', true);
const reworkRate = agent.rework_rate;
const reworkColor = reworkRate > 20 ? colors.kai : reworkRate > 10 ? colors.simon : colors.text;
const reworkColor = reworkRate > 20 ? colors.kai : reworkRate > 10 ? colors.human : colors.text;
reworkCell.text(reworkRate + '%')
.style('color', reworkColor);

Expand Down
2 changes: 1 addition & 1 deletion archaeology/visualization/github_fetcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pathlib import Path


_DEFAULT_OWNER = os.environ.get("ARCHAEOLOGY_GITHUB_OWNER", "Pastorsimon1798")
_DEFAULT_OWNER = os.environ.get("ARCHAEOLOGY_GITHUB_OWNER", "")


def _gh(*args):
Expand Down
4 changes: 2 additions & 2 deletions projects/demo-project/deliverables/archaeology.html
Original file line number Diff line number Diff line change
Expand Up @@ -449,10 +449,10 @@ <h2><span class="era-dot" style="background:#e599f7"></span>The Learning Curve</
<div class="callout" style="background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);border:1px solid #e599f7;border-radius:8px;padding:1rem 1.25rem;margin:0.75rem 0 1.25rem">
<div style="display:flex;align-items:center;gap:0.6rem;margin-bottom:0.5rem">
<span style="font-size:1.4rem">&#127775;</span>
<strong style="color:#e599f7;font-size:0.95rem">KEY PERSONJake Van Clief</strong>
<strong style="color:#e599f7;font-size:0.95rem">KEY INSIGHTContext Methodology</strong>
</div>
<p style="color:var(--text2);font-size:0.85rem;margin:0;line-height:1.5">
Jake invented <strong style="color:var(--text)">ICM (Interpreted Context Methodology)</strong> — the "folder system" that broke the iteration trap. His video on the topic was watched in Oct 2025 during the Ramp phase. Simon's <strong style="color:var(--text)">first-ever PR</strong> was to Jake's ICM repo (the <code>workspaces</code> commit on Feb 22). A second PR to <code>mcp-video</code> was merged into an MCP aggregator on GitHub. ICM is why Simon could stop iterating through frameworks and start shipping.
A structured context methodology — the "folder system" approach — broke the iteration trap. A video on the topic was watched during the Ramp phase. The developer's first external PR contributed to this methodology's public repo. ICM is why iterating through frameworks stopped and shipping started.
</p>
</div>
<div class="chart-grid">
Expand Down
4 changes: 2 additions & 2 deletions projects/demo-project/deliverables/visuals/archaeology.html
Original file line number Diff line number Diff line change
Expand Up @@ -449,10 +449,10 @@ <h2><span class="era-dot" style="background:#e599f7"></span>The Learning Curve</
<div class="callout" style="background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);border:1px solid #e599f7;border-radius:8px;padding:1rem 1.25rem;margin:0.75rem 0 1.25rem">
<div style="display:flex;align-items:center;gap:0.6rem;margin-bottom:0.5rem">
<span style="font-size:1.4rem">&#127775;</span>
<strong style="color:#e599f7;font-size:0.95rem">KEY PERSONJake Van Clief</strong>
<strong style="color:#e599f7;font-size:0.95rem">KEY INSIGHTContext Methodology</strong>
</div>
<p style="color:var(--text2);font-size:0.85rem;margin:0;line-height:1.5">
Jake invented <strong style="color:var(--text)">ICM (Interpreted Context Methodology)</strong> — the "folder system" that broke the iteration trap. His video on the topic was watched in Oct 2025 during the Ramp phase. Simon's <strong style="color:var(--text)">first-ever PR</strong> was to Jake's ICM repo (the <code>workspaces</code> commit on Feb 22). A second PR to <code>mcp-video</code> was merged into an MCP aggregator on GitHub. ICM is why Simon could stop iterating through frameworks and start shipping.
A structured context methodology — the "folder system" approach — broke the iteration trap. A video on the topic was watched during the Ramp phase. The developer's first external PR contributed to this methodology's public repo. ICM is why iterating through frameworks stopped and shipping started.
</p>
</div>
<div class="chart-grid">
Expand Down
Loading