#!/usr/bin/env bash # o-o Living Document — self-updating via LLM agent # To update: bash anthropic-leadership.o-o.html [--agent claude] [--model sonnet] # To read: open anthropic-leadership.o-o.html in any browser : << 'OO_HTML' Anthropic Leadership Team
← Back to index

Anthropic Leadership Team

As of Version 0

Overview

Anthropic is an American artificial intelligence safety company founded in 2021 by siblings Dario and Daniela Amodei, along with six other former OpenAI researchers. The company is structured as a public benefit corporation (PBC) and is headquartered in San Francisco, California. Anthropic develops the Claude family of AI assistants and is one of the leading AI research organizations globally. In February 2026, the company closed a $30 billion Series G funding round at a $380 billion post-money valuation, led by Coatue and GIC [s1][s2][s17].

The leadership team combines deep expertise in AI research, safety, and scaling with experienced operators from major technology companies. Eight co-founders remain actively involved in the company. Since late 2024, Anthropic has significantly expanded its executive ranks with hires across finance, product, commercial, infrastructure, and security functions—including a new CTO, Chief Commercial Officer, and CISO—as the company prepares for a potential IPO and scales toward an annualized revenue run rate of approximately $14 billion [s1][s3][s18].

Co-Founders

Dario Amodei — CEO & Co-Founder

Dario Amodei speaking at TechCrunch Disrupt 2023
Dario Amodei, CEO and co-founder of Anthropic. Source: Wikimedia Commons

Dario Amodei is an AI researcher and entrepreneur serving as CEO and co-founder of Anthropic. He holds a bachelor's degree in Physics from Caltech and Stanford and a PhD in Computational Neuroscience from Princeton University. Before founding Anthropic, Amodei worked at Baidu (2014–2015), then at Google, before joining OpenAI in 2016 where he rose to Vice President of Research [s4][s5].

Dario departed OpenAI in 2020 over concerns about the pace of commercialization relative to safety research, and co-founded Anthropic in 2021. He has been a prominent voice advocating for responsible AI development while pursuing frontier model capabilities [s4][s5].

Daniela Amodei — President & Co-Founder

Daniela Amodei serves as President and co-founder of Anthropic. She graduated from University of California, Santa Cruz with a Bachelor of Arts in English Literature, having originally attended on a scholarship for classical flute performance. Her early career spanned global health and politics, including managing communications for U.S. Representative Matt Cartwright [s6].

In 2013, Daniela joined Stripe as an early employee, then transitioned to OpenAI in 2018, where she managed the operations team during GPT-2's development and later served as Vice President of Safety and Policy. She co-founded Anthropic in 2021 with her brother Dario and oversees the company's business operations, go-to-market strategy, policy, and people functions [s6][s2].

Other Co-Founders

Six additional co-founders, all former OpenAI researchers, round out the founding team [s2][s7]:

Tom Brown — Co-Founder. Lead author of the GPT-3 paper at OpenAI, Brown brought deep expertise in large language model training to Anthropic.

Jack Clark — Co-Founder. Clark focuses on AI policy, strategy, and communications at Anthropic. He previously served as Policy Director at OpenAI and is known for his work on the social implications of AI systems.

Jared Kaplan — Co-Founder & Chief Science Officer. Kaplan leads Anthropic's scientific research agenda. He is a physicist by training and is known for co-authoring influential papers on neural scaling laws.

Sam McCandlish — Co-Founder & Chief Architect. McCandlish served as Anthropic's original CTO and transitioned to the Chief Architect role in October 2025, where he focuses on pre-training and large-scale model architecture. He previously contributed to scaling research at OpenAI [s19].

Ben Mann — Co-Founder. Mann is a software engineer who helped build GPT-3 at OpenAI. At Anthropic, he founded the Labs team in mid-2024 to bridge research and end-user products, and currently co-leads the expanded Labs division [s20].

Christopher Olah — Co-Founder & Head of Interpretability. Olah is a leading researcher in mechanistic interpretability—the science of understanding neural networks by reverse-engineering their internal representations into human-understandable algorithms [s8][s9].

Executive Team

Krishna Rao — Chief Financial Officer

Krishna Rao joined Anthropic as its first CFO in May 2024. He brings nearly 20 years of experience in strategic finance, joining from Fanatics Commerce where he served as CFO. Prior to Fanatics, Rao held senior finance roles at Airbnb, where he was a key executive during the company's IPO and growth phase [s10][s11].

Rahul Patil — Chief Technology Officer

Rahul Patil joined Anthropic as Chief Technology Officer in October 2025, succeeding co-founder Sam McCandlish. Patil previously served as CTO at Stripe, where he led engineering and global operations for over five years, and held prior leadership roles at Oracle Cloud Infrastructure, Amazon Web Services, and Microsoft Azure. He oversees Anthropic's engineering organization across product, compute, infrastructure, inference, data science, and security, reporting to President Daniela Amodei [s19][s21].

Paul Smith — Chief Commercial Officer

Paul Smith joined Anthropic as its first Chief Commercial Officer in August 2025. He brings over 30 years of experience building and scaling global go-to-market organizations at Microsoft, Salesforce, and ServiceNow, where he most recently served as President of Global Customer and Field Operations. Smith leads sales, partnerships, revenue operations, and enterprise marketing [s22][s23].

Ami Vora — Head of Product

Ami Vora joined Anthropic in late 2025 and took over the Product organization in January 2026, following Mike Krieger's transition to the Labs division. She previously held senior product roles at Faire, Meta's WhatsApp, and Facebook. Vora focuses on scaling Claude for enterprise and consumer markets [s24][s25].

Mike Krieger — Co-Lead, Labs

Mike Krieger, co-founder of Instagram, joined Anthropic as Chief Product Officer in 2024. In January 2026, Krieger transitioned to co-lead Anthropic's Labs division alongside co-founder Ben Mann, reporting to President Daniela Amodei. Labs is an internal incubator responsible for experimental products at the frontier of Claude's capabilities, including Claude Code and MCP [s12][s26].

Jan Leike — Head of Alignment Science

Jan Leike joined Anthropic in mid-2024 to co-lead the Alignment Science team, departing from OpenAI where he had led the Superalignment team. Leike holds a PhD in reinforcement learning theory from the Australian National University and previously worked at DeepMind, where he prototyped reinforcement learning from human feedback (RLHF) techniques [s2][s13].

Security Leadership

Vitaly Gudanets — Chief Information Security Officer. Gudanets joined Anthropic in late 2025, bringing over 30 years of experience across security engineering, privacy, and governance from leadership roles at Netflix, Google, Zendesk, and Symantec [s27].

Jason Clinton — Deputy CISO. Clinton was Anthropic's first CISO, joining in April 2023 after more than a decade at Google leading Chrome infrastructure security. He transitioned to Deputy CISO following Gudanets's appointment [s27].

Commercial Leadership

Chris Ciauri — Managing Director, International. Ciauri joined Anthropic to lead the company's global expansion outside of the United States, building on an enterprise sales background [s3].

Guillaume Princen — Head of EMEA. Princen oversees Anthropic's European, Middle Eastern, and African operations [s3].

Hidetoshi Tojo — Head of Japan. Tojo leads Anthropic's market efforts in Japan [s3].

Kate Jensen — Head of Americas. Jensen leads Anthropic's commercial operations in the Americas region [s3].

Thiyagu Ramasamy — Head of Public Sector. Ramasamy joined in January 2025 from Amazon Web Services, where he led data, analytics, and AI/ML initiatives for public sector customers. He oversees Anthropic's go-to-market strategy for federal, state, and local government agencies [s28].

Board of Directors

As of February 2026, Anthropic's board of directors consists of six members [s14][s15][s16]:

Dario Amodei — Co-Founder and CEO of Anthropic.

Daniela Amodei — Co-Founder and President of Anthropic.

Yasmin Razavi — General Partner at Spark Capital, one of Anthropic's early investors.

Jay Kreps — Co-Founder and CEO of Confluent, the data streaming platform company. Kreps was appointed to Anthropic's board to bring expertise in enterprise technology and data infrastructure [s16].

Reed Hastings — Co-Founder and former CEO of Netflix. Hastings brings decades of experience scaling technology companies and navigating complex strategic decisions [s14].

Chris Liddell — Former CFO of Microsoft and former Deputy White House Chief of Staff. Liddell was appointed in February 2026 and brings extensive corporate finance and governance experience, including roles as a director of Commonwealth Fusion Systems and the Council on Foreign Relations [s15].

Long-Term Benefit Trust

Anthropic maintains a Long-Term Benefit Trust (LTBT), a purpose trust established for "the responsible development and maintenance of advanced AI for the long-term benefit of humanity." The LTBT holds Class T shares in Anthropic's PBC structure, granting it the power to elect directors to the board. As of October 2025, the Trust members are Neil Buddy Shah, Kanika Bahl, Zach Robinson, and Richard Fontaine [s2][s14].

Research Leadership

Anthropic's research organization is led by several co-founders and senior researchers who drive the company's work on frontier AI capabilities and safety [s2][s8]:

Jared Kaplan, Chief Science Officer at Anthropic
Jared Kaplan, Chief Science Officer. Source: Wikimedia Commons

Jared Kaplan (Chief Science Officer) sets the overall scientific direction, drawing on his background in physics and neural scaling laws. His research on how model performance scales with compute, data, and parameters has been foundational to the field [s7].

Sam McCandlish (Chief Architect, formerly CTO) focuses on pre-training and large-scale model architecture, having transitioned from the CTO role in October 2025 to allow dedicated attention to the challenge of training ever-larger models [s7][s19].

Christopher Olah heads the interpretability research team, pioneering techniques to understand what neural networks learn and how they process information internally. His work on mechanistic interpretability is considered foundational to the field of AI safety [s8][s9].

Jan Leike leads the Alignment Science team, which focuses on ensuring AI systems behave in accordance with human intentions. His prior work on RLHF at DeepMind and superalignment research at OpenAI directly informs Anthropic's approach to AI safety [s13].

In January 2026, Anthropic expanded its "Labs" division, an internal incubator originally founded by co-founder Ben Mann in mid-2024. Former CPO Mike Krieger now co-leads Labs alongside Mann, with the team responsible for experimental products including Claude Code, MCP, and Cowork. The division reports to President Daniela Amodei and is actively hiring to double its headcount [s12][s20][s26].

References

  1. [s1] Anthropic — Company, anthropic.com
  2. [s2] Anthropic — Wikipedia, wikipedia.org
  3. [s3] Anthropic Expands Global Leadership in Enterprise AI, anthropic.com
  4. [s4] Dario Amodei — Wikipedia, wikipedia.org
  5. [s5] Dario Amodei — Personal Site, darioamodei.com
  6. [s6] Daniela Amodei — Wikipedia, wikipedia.org
  7. [s7] List of Anthropic Executives & Org Chart, clay.com
  8. [s8] About Me — colah's blog, colah.github.io
  9. [s9] Anthropic Business Breakdown & Founding Story, contrary.com
  10. [s10] Krishna Rao joins Anthropic as Chief Financial Officer, anthropic.com
  11. [s11] AI startup Anthropic brings in Airbnb alum as first CFO, cfodive.com
  12. [s12] Anthropic CEO, Founder, Key Executive Team, cbinsights.com
  13. [s13] Anthropic's Power Players, b17news.com
  14. [s14] Anthropic: Former Trump aide Liddell on board of directors, cnbc.com
  15. [s15] Chris Liddell appointed to Anthropic's board of directors, anthropic.com
  16. [s16] Jay Kreps appointed to Anthropic's Board of Directors, anthropic.com
  17. [s17] Anthropic closes $30 billion funding round at $380 billion valuation, cnbc.com
  18. [s18] Anthropic CEO Dario Amodei explains his spending caution, fortune.com
  19. [s19] Anthropic hires new CTO with focus on AI infrastructure, techcrunch.com
  20. [s20] Anthropic co-founder Ben Mann on Lenny's Podcast, lennysnewsletter.com
  21. [s21] Rahul Patil joins Anthropic as Chief Technology Officer, anthropic.com
  22. [s22] Paul Smith to join Anthropic as Chief Commercial Officer, anthropic.com
  23. [s23] Anthropic executive takes a thinly-veiled swipe at OpenAI over spending and ads, cnbc.com
  24. [s24] Anthropic Moves Chief Product Officer Krieger to Labs Group, theinformation.com
  25. [s25] Anthropic shakes up its C-suite, bensbites.com
  26. [s26] Introducing Anthropic Labs, anthropic.com
  27. [s27] Anthropic brings in new CISO, ramps up security hiring, thestack.technology
  28. [s28] AI startup Anthropic to build out public sector team, nextgov.com
OO_HTML set -euo pipefail SELF="$(cd "$(dirname "$0")" && pwd -P)/$(basename "$0")" SELF_DIR="$(dirname "$SELF")" SELF_NAME="$(basename "$SELF")" # OO:SHELL:START # ─── DOCUMENT TEMPLATE ──────────────────────────────────────── generate_oo_file() { local filepath="$1" title="$2" scope="$3" slug="$4" # Extract shared section line numbers from THIS file local css_s css_e js_s js_e sh_s sh_e css_s=$(grep -n '^$' "$SELF" | head -1 | cut -d: -f1) css_e=$(grep -n '^$' "$SELF" | head -1 | cut -d: -f1) js_s=$(grep -n '^$' "$SELF" | head -1 | cut -d: -f1) js_e=$(grep -n '^$' "$SELF" | head -1 | cut -d: -f1) sh_s=$(grep -n '^# OO:SHELL:START$' "$SELF" | head -1 | cut -d: -f1) sh_e=$(grep -n '^# OO:SHELL:END$' "$SELF" | head -1 | cut -d: -f1) # Part 1: shebang + heredoc start + HTML head (before CSS) cat > "$filepath" << 'TPL_HEAD' #!/usr/bin/env bash # o-o Living Document — self-updating via LLM agent # To update: bash __SLUG__.o-o.html [--agent claude] [--model sonnet] # To read: open __SLUG__.o-o.html in any browser : << 'OO_HTML' __TITLE__ TPL_HEAD # Inject CSS from this file (between OO:CSS markers, inclusive) sed -n "${css_s},${css_e}p" "$SELF" >> "$filepath" # Part 2: close head + body + header + article stub + manifest cat >> "$filepath" << 'TPL_BODY'
← Back to index

__TITLE__

As of Version 0

This document has not been populated yet.

To fill it with researched content, run:

bash __SLUG__.o-o.html

TPL_BODY # Inject JS from this file (between OO:JS markers, inclusive) sed -n "${js_s},${js_e}p" "$SELF" >> "$filepath" # Part 3: contract + machine zone + close HTML + OO_HTML terminator + shell preamble cat >> "$filepath" << 'TPL_CONTRACT' OO_HTML set -euo pipefail SELF="$(cd "$(dirname "$0")" && pwd -P)/$(basename "$0")" SELF_DIR="$(dirname "$SELF")" SELF_NAME="$(basename "$SELF")" TPL_CONTRACT # Inject shell block from this file (between OO:SHELL markers, inclusive) sed -n "${sh_s},${sh_e}p" "$SELF" >> "$filepath" # Part 4: exit printf '\nexit 0\n' >> "$filepath" # Replace placeholders local tmp="/tmp/oo_template_$$" sed -e "s|__TITLE__|${title}|g" \ -e "s|__SCOPE__|${scope}|g" \ -e "s|__SLUG__|${slug}|g" \ -e "s|__YEAR__|$(date +%Y)|g" \ "$filepath" > "$tmp" && mv "$tmp" "$filepath" chmod +x "$filepath" } # ─── UTILITIES ──────────────────────────────────────────────── slugify() { local str="$1" echo "$str" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed 's/[^a-z0-9-]//g' | cut -c1-60 } # ─── INDEX MANAGEMENT ───────────────────────────────────────── rebuild_index() { echo "o-o Index: Scanning for .o-o.html files..." local count=0 local table_rows="" local card_data="" # Find all .o-o.html files (excluding index.o-o.html) while IFS= read -r file; do [[ "$file" == "$SELF" ]] && continue # Extract manifest fields using grep (portable, no jq) local title=$(grep -o '"title"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:[[:space:]]*"//' | sed 's/"$//') local version=$(grep -o '"version"[[:space:]]*:[[:space:]]*[0-9]*' "$file" | head -1 | grep -o '[0-9]*$') local as_of=$(grep -o '"as_of"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:[[:space:]]*"//' | sed 's/"$//') local update_days=$(grep -o '"update_every_days"[[:space:]]*:[[:space:]]*[0-9]*' "$file" | head -1 | grep -o '[0-9]*$' || echo "7") # Get file info local rel_path=$(basename "$file") local file_size=$(ls -lh "$file" | awk '{print $5}') # Default values [[ -z "$title" ]] && title="Untitled" [[ -z "$version" ]] && version="0" [[ -z "$as_of" ]] && as_of="—" # Build table row table_rows="${table_rows} ${title} ${file_size} ${as_of} ${version} " # Collect card data (sort_date|title|rel_path|display_date|excerpt|update_days) local excerpt="" excerpt=$(awk '/
/){gsub(/<[^>]*>/,"");gsub(/&/,"\\&");gsub(/—/,"—");gsub(/\[s[0-9]+\]/,"");gsub(/^[[:space:]]+|[[:space:]]+$/,"");print substr($0,1,120);exit}}' "$file") [[ -n "$excerpt" ]] && excerpt="${excerpt}..." local sort_date="$as_of" [[ "$sort_date" == "—" || -z "$sort_date" ]] && sort_date="0000-00-00" card_data="${card_data}${sort_date}|${title}|${rel_path}|${as_of}|${excerpt}|${update_days} " count=$((count + 1)) done < <(find "$SELF_DIR" -name "*.o-o.html" -type f) # Build card grid (top 8 most recently updated) local card_html="" if [[ -n "$card_data" ]]; then local sorted_cards sorted_cards=$(echo "$card_data" | grep -v '^$' | sort -t'|' -k1 -r | head -8) while IFS='|' read -r c_sort c_title c_path c_date c_excerpt c_update_days; do [[ -z "$c_title" ]] && continue local c_badge="" if [[ -n "$c_date" && "$c_date" != "—" ]]; then # Format date nicely: 2026-02-16 → Feb 16, 2026 local nice_date="$c_date" if date -j -f "%Y-%m-%d" "$c_date" "+%b %-d, %Y" &>/dev/null 2>&1; then nice_date=$(date -j -f "%Y-%m-%d" "$c_date" "+%b %-d, %Y") elif date -d "$c_date" "+%b %-d, %Y" &>/dev/null 2>&1; then nice_date=$(date -d "$c_date" "+%b %-d, %Y") fi # Check freshness based on update_every_days local badge_class="fresh" local now_epoch=$(date +%s) local date_epoch="" if date -j -f "%Y-%m-%d" "$c_date" "+%s" &>/dev/null 2>&1; then date_epoch=$(date -j -f "%Y-%m-%d" "$c_date" "+%s") elif date -d "$c_date" "+%s" &>/dev/null 2>&1; then date_epoch=$(date -d "$c_date" "+%s") fi if [[ -n "$date_epoch" ]]; then local age=$(( now_epoch - date_epoch )) local stale_threshold=$(( ${c_update_days:-7} * 86400 )) [[ "$age" -gt "$stale_threshold" ]] && badge_class="stale" fi c_badge="${nice_date}" else c_badge="New" fi card_html="${card_html} ${c_title} ${c_badge} ${c_excerpt} " done <<< "$sorted_cards" fi # Build the new content local now=$(date "+%Y-%m-%d %H:%M") local new_content if [[ "$count" -eq 0 ]]; then new_content='

No documents found.

Create one with:

bash index.o-o.html --new "Your Topic"

' else new_content="
${card_html}
${table_rows}
Title Size Last Updated Version
" fi # Escape special characters for perl regex local escaped_content=$(echo "$new_content" | sed 's/\\/\\\\/g' | sed 's/\$/\\$/g' | sed 's/@/\\@/g') # Update the index using perl (works reliably with multiline content) perl -i -pe "BEGIN{undef \$/;} s|.*?|\n${escaped_content}\n |sm" "$SELF" # Update stats local tmp="/tmp/oo_stats_$$" sed -e "s|[^<]*|$count|" \ -e "s|[^<]*|$now|" \ "$SELF" > "$tmp" && mv "$tmp" "$SELF" echo "o-o Index: Found $count document(s). Index updated." } create_new() { local input="$1" local title desc # Split on " / " if present if [[ "$input" == *" / "* ]]; then title="${input%% / *}" desc="${input##* / }" else title="$input" desc="$input" fi # Slugify title for filename local slug=$(slugify "$title") local filepath="${SELF_DIR}/${slug}.o-o.html" # Check if file exists if [[ -e "$filepath" ]]; then echo "o-o: Error — file already exists: $filepath" >&2 exit 1 fi echo "o-o: Creating new document: $title" echo "o-o: File: $filepath" # Generate the file generate_oo_file "$filepath" "$title" "$desc" "$slug" echo "o-o: Created $filepath" echo "o-o: Running first update..." # Run the file to trigger first update bash "$filepath" echo "o-o: Document created and populated. Open in browser to read." } update_all() { local force="${1:-0}" echo "o-o: Checking for stale documents..." local now_epoch=$(date +%s) local updated_count=0 while IFS= read -r file; do [[ "$file" == "$SELF" ]] && continue local as_of=$(grep -o '"as_of"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | head -1 | sed 's/.*:[[:space:]]*"//' | sed 's/"$//') local update_days=$(grep -o '"update_every_days"[[:space:]]*:[[:space:]]*[0-9]*' "$file" | head -1 | grep -o '[0-9]*$' || true) update_days="${update_days:-7}" local should_update=0 if [[ "$force" -eq 1 ]]; then should_update=1 elif [[ -z "$as_of" || "$as_of" == "null" ]]; then should_update=1 else local fresh_secs=$((update_days * 86400)) local as_of_epoch if date -j -f "%Y-%m-%d" "$as_of" "+%s" &>/dev/null; then as_of_epoch=$(date -j -f "%Y-%m-%d" "$as_of" "+%s") elif date -d "$as_of" "+%s" &>/dev/null; then as_of_epoch=$(date -d "$as_of" "+%s") else should_update=1 fi if [[ -n "${as_of_epoch:-}" && "$should_update" -eq 0 ]]; then local age=$((now_epoch - as_of_epoch)) if [[ "$age" -gt "$fresh_secs" ]]; then should_update=1 fi fi fi if [[ "$should_update" -eq 1 ]]; then echo "o-o: Updating $(basename "$file")..." if [[ "$force" -eq 1 ]]; then bash "$file" --force else bash "$file" fi updated_count=$((updated_count + 1)) else echo "o-o: $(basename "$file") is still fresh. Skipping." fi done < <(find "$SELF_DIR" -name "*.o-o.html" -type f) if [[ "$updated_count" -gt 0 ]]; then echo "o-o: Updated $updated_count document(s)." echo "o-o: Rebuilding index..." rebuild_index else echo "o-o: All documents are up to date." fi } # ─── SYNC ───────────────────────────────────────────────────── sync_section() { local section="$1" local sm em case "$section" in css) sm='' em='' ;; js) sm='' em='' ;; shell) sm='# OO:SHELL:START' em='# OO:SHELL:END' ;; all) sync_section css; sync_section js; sync_section shell; return ;; *) echo "o-o Sync: Unknown section '$section'. Use: css, js, shell, all" >&2; exit 1 ;; esac # Extract canonical section boundaries from THIS file local start_line end_line start_line=$(grep -n "^${sm}\$" "$SELF" | head -1 | cut -d: -f1) end_line=$(grep -n "^${em}\$" "$SELF" | head -1 | cut -d: -f1) if [[ -z "$start_line" || -z "$end_line" ]]; then echo "o-o Sync: ERROR — no $section markers found in $SELF_NAME" >&2 return 1 fi local synced=0 for file in "$SELF_DIR"/*.o-o.html; do [[ "$file" == "$SELF" ]] && continue local f_start f_end f_start=$(grep -n "^${sm}\$" "$file" | head -1 | cut -d: -f1 || true) f_end=$(grep -n "^${em}\$" "$file" | head -1 | cut -d: -f1 || true) if [[ -z "$f_start" || -z "$f_end" ]]; then echo "o-o Sync: SKIP $(basename "$file") (no $section markers)" continue fi # Assemble: content before marker + canonical section + content after marker { head -n $((f_start - 1)) "$file" sed -n "${start_line},${end_line}p" "$SELF" tail -n +$((f_end + 1)) "$file" } > "${file}.tmp" && mv "${file}.tmp" "$file" synced=$((synced + 1)) echo "o-o Sync: $(basename "$file") [$section]" done # Handle custom oo.css for CSS sync if [[ "$section" == "css" ]]; then local custom_css="$SELF_DIR/oo.css" local csm='' local cem='' for file in "$SELF_DIR"/*.o-o.html; do # Remove existing custom block if present local c_start c_end c_start=$(grep -n "^${csm}\$" "$file" 2>/dev/null | head -1 | cut -d: -f1 || true) c_end=$(grep -n "^${cem}\$" "$file" 2>/dev/null | head -1 | cut -d: -f1 || true) if [[ -n "$c_start" && -n "$c_end" ]]; then { head -n $((c_start - 1)) "$file" tail -n +$((c_end + 1)) "$file" } > "${file}.tmp" && mv "${file}.tmp" "$file" fi # If oo.css exists, inject it right after OO:CSS:END if [[ -f "$custom_css" ]]; then local css_end_line css_end_line=$(grep -n "^${em}\$" "$file" | head -1 | cut -d: -f1) if [[ -n "$css_end_line" ]]; then { head -n "$css_end_line" "$file" echo "$csm" echo "" echo "$cem" tail -n +$((css_end_line + 1)) "$file" } > "${file}.tmp" && mv "${file}.tmp" "$file" fi fi done fi echo "o-o Sync: $section synced to $synced file(s)." } # ─── HELP ───────────────────────────────────────────────────── show_help() { echo "o-o — self-updating living documents" echo "" echo "Usage:" echo " bash $SELF_NAME [OPTIONS]" echo "" if [[ "$IS_INDEX" -eq 1 ]]; then echo "Index commands:" echo " (no args) Rebuild the index" echo " --new Create new document (interactive)" echo " --new \"Title / description\" Create new document (quick)" echo " --update-all Update stale documents" echo " --update-all --force Force update all documents" echo "" else echo "Article commands:" echo " (no args) Update this document" echo "" fi echo "Shared options:" echo " --show Show current contract and config" echo " --set KEY VALUE Set a contract/config field" echo " --add intent|section VALUE Add to a research array field" echo " --remove intent|section VALUE Remove from a research array field" echo " --sync [css|js|shell|all] Sync shared sections to sibling files" echo " --agent NAME Agent backend: claude (default)" echo " --model NAME Override model (e.g. opus, sonnet, haiku)" echo " --force Update even if document is still fresh" echo " --help, -h Show this help" echo "" echo "Settable fields (--set):" echo " subject, scope, audience, tone, budget, update_every_days" echo "" echo "Array fields (--add / --remove):" echo " intent Research search queries" echo " section Required article sections" echo "" echo "Examples:" if [[ "$IS_INDEX" -eq 1 ]]; then echo " bash $SELF_NAME --new \"History of the USA\"" echo " bash $SELF_NAME --new \"Python Async / Guide to async/await patterns\"" echo " bash $SELF_NAME --update-all" else echo " bash $SELF_NAME # Update with latest research" echo " bash $SELF_NAME --force # Force update even if fresh" echo " bash $SELF_NAME --model opus # Use a specific model" fi echo " bash $SELF_NAME --set scope \"US market analysis\"" echo " bash $SELF_NAME --add intent \"quarterly earnings 2026\"" echo " bash $SELF_NAME --add section \"Market Analysis\"" echo " bash $SELF_NAME --remove intent \"old search query\"" echo " bash $SELF_NAME --sync all # Propagate shared code to siblings" } # ─── ARG PARSING ────────────────────────────────────────────── ACTION="" NEW_TOPIC="" SYNC_SECTION="" AGENT="claude" MODEL="" FORCE=0 while [[ $# -gt 0 ]]; do case "$1" in --new) ACTION="new"; NEW_TOPIC="${2:-}"; [[ -n "$NEW_TOPIC" ]] && shift; shift ;; --update-all) ACTION="update-all"; shift ;; --sync) ACTION="sync"; SYNC_SECTION="${2:-all}"; shift; [[ $# -gt 0 && "${1:0:2}" != "--" ]] && shift ;; --show) ACTION="show"; shift ;; --set) ACTION="set"; SET_KEY="${2:-}"; SET_VAL="${3:-}"; shift; [[ -n "$SET_KEY" ]] && shift; [[ -n "$SET_VAL" ]] && shift ;; --add) ACTION="add"; ARR_FIELD="${2:-}"; ARR_VAL="${3:-}"; shift; [[ -n "$ARR_FIELD" ]] && shift; [[ -n "$ARR_VAL" ]] && shift ;; --remove) ACTION="remove"; ARR_FIELD="${2:-}"; ARR_VAL="${3:-}"; shift; [[ -n "$ARR_FIELD" ]] && shift; [[ -n "$ARR_VAL" ]] && shift ;; --agent) AGENT="$2"; shift 2 ;; --model) MODEL="$2"; shift 2 ;; --force) FORCE=1; shift ;; --help|-h) ACTION="help"; shift ;; *) echo "o-o: Unknown option: $1 (try --help)" >&2; exit 1 ;; esac done IS_INDEX=0 [[ "$SELF_NAME" == index* ]] && IS_INDEX=1 # ─── FRESHNESS CHECK ────────────────────────────────────────── check_freshness() { [[ "$FORCE" -eq 1 ]] && return 1 # return 1 = not fresh, should update local update_days as_of update_days=$(grep -o '"update_every_days"[[:space:]]*:[[:space:]]*[0-9]*' "$SELF" | head -1 | grep -o '[0-9]*$' || true) update_days="${update_days:-7}" as_of=$(grep -o '"as_of"[[:space:]]*:[[:space:]]*"[^"]*"' "$SELF" | head -1 | sed 's/.*:[[:space:]]*"//' | sed 's/"$//') [[ -z "$as_of" ]] && return 1 # no date = needs update local fresh_secs=$((update_days * 86400)) local now_epoch=$(date +%s) local as_of_epoch="" if date -j -f "%Y-%m-%d" "$as_of" "+%s" &>/dev/null 2>&1; then as_of_epoch=$(date -j -f "%Y-%m-%d" "$as_of" "+%s") elif date -d "$as_of" "+%s" &>/dev/null 2>&1; then as_of_epoch=$(date -d "$as_of" "+%s") fi if [[ -n "$as_of_epoch" ]]; then local age=$(( now_epoch - as_of_epoch )) if [[ "$age" -lt "$fresh_secs" ]]; then echo "o-o: '$SELF_NAME' is still fresh (updated $as_of, updates every ${update_days}d). Skipping." echo "o-o: Use --force to update anyway." return 0 # fresh, skip fi fi return 1 # not fresh, should update } # ─── AGENT DISPATCH ─────────────────────────────────────────── dispatch_update() { # Extract budget from contract local budget budget=$(grep -o '"max_cost_usd"[[:space:]]*:[[:space:]]*[0-9.]*' "$SELF" | head -1 | grep -o '[0-9.]*$' || true) budget="${budget:-0.50}" # Build the prompt local prompt read -r -d '' prompt << 'PROMPT_EOF' || true You are a o-o research agent. Your task is to update a living document. The document is at: __SELF__ This file is a polyglot HTML/bash file structured as follows: - Above window.stop(): browser-visible content (article, CSS, JS, manifest) - Below window.stop(): machine-readable zone (update contract, source cache, changelog) Read the update contract (the JSON block with id="oo-contract") — it contains your complete instructions: the subject, research intents, required sections, quality thresholds, source policy, and output format rules. Check the oo-manifest "as_of" field for when this document was last updated. If empty, this is a first run — research everything. If it has a date, focus your research on new information since that date. Use the Edit tool to modify specific parts of the file in-place. Only modify:
content, oo-manifest, oo-source-cache, oo-changelog. Do NOT touch CSS, JavaScript, the shell preamble, or structural HTML outside
. IMAGES: The contract may have an "images" section. If images are allowed: - Find relevant images via web search (official sites, wikimedia, press kits) - Download with: curl -sL "" -o /tmp/oo_img_N.ext - Verify it is an image: file /tmp/oo_img_N.ext - Resize (preserve format — keep PNG for transparency, JPEG for photos): macOS: sips --resampleWidth /tmp/oo_img_N.ext --out /tmp/oo_img_N_r.ext Linux: convert /tmp/oo_img_N.ext -resize x /tmp/oo_img_N_r.ext - Check size: if over max_file_kb, reduce further or skip - Encode: base64 < /tmp/oo_img_N_r.ext - Embed as:
description
Caption. Source: domain
- Clean up: rm /tmp/oo_img_N* PROMPT_EOF # Replace __SELF__ placeholder with actual path prompt="${prompt//__SELF__/$SELF}" echo "o-o: Updating '$SELF_NAME' via $AGENT (budget: \$$budget)..." case "$AGENT" in claude) if ! command -v claude &>/dev/null; then echo "o-o: Error — 'claude' CLI not found." >&2 echo "o-o: Install: https://docs.anthropic.com/en/docs/claude-code" >&2 exit 1 fi local -a claude_args=( -p "$prompt" --allowed-tools "Bash,Read,Edit,WebSearch,WebFetch" --max-budget-usd "$budget" ) if [[ -n "$MODEL" ]]; then claude_args+=(--model "$MODEL") fi claude "${claude_args[@]}" ;; *) echo "o-o: Unknown agent '$AGENT'." >&2 echo "o-o: Currently supported: claude" >&2 exit 1 ;; esac echo "o-o: Update complete. Open '$SELF_NAME' in a browser to read." } # ─── COMMAND ROUTER ─────────────────────────────────────────── # ─── SHOW CONTRACT ──────────────────────────────────────────── show_contract() { echo "" echo " $SELF_NAME" echo " ────────────────────────" # Extract manifest fields local manifest contract manifest=$(perl -0777 -ne 'print $1 if /id="oo-manifest"[^>]*>\s*(\{.*?\})\s*<\/script>/s' "$SELF") contract=$(perl -0777 -ne 'print $1 if /id="oo-contract"[^>]*>\s*(\{.*?\})\s*<\/script>/s' "$SELF") if [[ -n "$manifest" ]]; then local title as_of version update_days title=$(echo "$manifest" | perl -ne 'print $1 if /"title"\s*:\s*"([^"]*)"/') as_of=$(echo "$manifest" | perl -ne 'print $1 if /"as_of"\s*:\s*"([^"]*)"/') version=$(echo "$manifest" | perl -ne 'print $1 if /"version"\s*:\s*(\d+)/') update_days=$(echo "$manifest" | perl -ne 'print $1 if /"update_every_days"\s*:\s*(\d+)/') [[ -n "$title" ]] && echo " Title: $title" [[ -n "$version" ]] && echo " Version: $version" [[ -n "$as_of" ]] && echo " Last updated: $as_of" [[ -n "$update_days" ]] && echo " Update every: ${update_days} days" fi if [[ -n "$contract" ]]; then local subject scope audience tone budget subject=$(echo "$contract" | perl -ne 'print $1 if /"subject"\s*:\s*"([^"]*)"/') scope=$(echo "$contract" | perl -ne 'print $1 if /"scope"\s*:\s*"([^"]*)"/') audience=$(echo "$contract" | perl -ne 'print $1 if /"audience"\s*:\s*"([^"]*)"/') tone=$(echo "$contract" | perl -ne 'print $1 if /"tone"\s*:\s*"([^"]*)"/') budget=$(echo "$contract" | perl -ne 'print $1 if /"max_cost_usd"\s*:\s*([\d.]+)/') echo "" [[ -n "$subject" ]] && echo " Subject: $subject" [[ -n "$scope" ]] && echo " Scope: $scope" [[ -n "$audience" ]] && echo " Audience: $audience" [[ -n "$tone" ]] && echo " Tone: $tone" [[ -n "$budget" ]] && echo " Budget: \$$budget" # Research intents local intents intents=$(echo "$contract" | perl -0777 -ne 'if(/"intents"\s*:\s*\[(.*?)\]/s){$i=$1; while($i=~/"([^"]+)"/g){print "$1\n"}}') if [[ -n "$intents" ]]; then echo "" echo " Research intents:" while IFS= read -r line; do echo " - $line" done <<< "$intents" fi # Required sections local sections sections=$(echo "$contract" | perl -0777 -ne 'if(/"required_sections"\s*:\s*\[(.*?)\]/s){$i=$1; while($i=~/"([^"]+)"/g){print "$1\n"}}') if [[ -n "$sections" ]]; then echo "" echo " Required sections:" while IFS= read -r line; do echo " - $line" done <<< "$sections" fi fi echo "" } # ─── SET FIELD ───────────────────────────────────────────────── set_field() { local key="$1" val="$2" [[ -z "$key" || -z "$val" ]] && { echo "o-o: Usage: --set KEY VALUE" >&2; exit 1; } case "$key" in subject|scope|audience|tone) # These live in oo-contract → identity.KEY perl -i -0pe "s/(\"identity\"\\s*:\\s*\\{[^}]*\"$key\"\\s*:\\s*\")([^\"]*)(\")/\${1}$val\${3}/s" "$SELF" echo "o-o: Set identity.$key = \"$val\"" ;; budget) # budget.max_cost_usd in oo-contract perl -i -pe "s/(\"max_cost_usd\"\\s*:\\s*)[\\d.]+/\${1}$val/" "$SELF" echo "o-o: Set budget.max_cost_usd = $val" ;; update_every_days) # In oo-manifest perl -i -pe "s/(\"update_every_days\"\\s*:\\s*)\\d+/\${1}$val/" "$SELF" echo "o-o: Set update_every_days = $val" ;; *) echo "o-o: Unknown field: $key" >&2 echo "o-o: Settable fields: subject, scope, audience, tone, budget, update_every_days" >&2 echo "o-o: For array fields use: --add intent|section VALUE / --remove intent|section VALUE" >&2 exit 1 ;; esac } # ─── ADD / REMOVE ARRAY ITEMS ────────────────────────────────── add_to_array() { local field="$1" value="$2" [[ -z "$field" || -z "$value" ]] && { echo "o-o: Usage: --add intent|section VALUE" >&2; exit 1; } local arr_name case "$field" in intent) arr_name="intents" ;; section) arr_name="required_sections" ;; *) echo "o-o: Unknown array field: $field (use: intent, section)" >&2; exit 1 ;; esac # Append before the closing ] of the named array perl -i -0777 -pe 's/("'"$arr_name"'"\s*:\s*\[.*?)(\s*\])/$1,\n "'"$value"'"$2/s' "$SELF" # Fix leading comma if array was previously empty: ["x"] → ["x"] perl -i -pe 's/\[\s*,\s*"/["/' "$SELF" echo "o-o: Added to research.$arr_name: \"$value\"" } remove_from_array() { local field="$1" value="$2" [[ -z "$field" || -z "$value" ]] && { echo "o-o: Usage: --remove intent|section VALUE" >&2; exit 1; } local arr_name case "$field" in intent) arr_name="intents" ;; section) arr_name="required_sections" ;; *) echo "o-o: Unknown array field: $field (use: intent, section)" >&2; exit 1 ;; esac # Remove line matching the exact value perl -i -ne 'print unless /^\s*"\Q'"$value"'\E"\s*,?\s*$/' "$SELF" # Fix trailing comma before ]: ..., ] → ...] perl -i -0777 -pe 's/,(\s*\])/$1/g' "$SELF" echo "o-o: Removed from research.$arr_name: \"$value\"" } case "$ACTION" in new) if [[ "$IS_INDEX" -eq 0 ]]; then echo "o-o: --new is only available on index files." >&2 echo "o-o: Rename this file to index*.o-o.html to enable library management." >&2 exit 1 fi if [[ -z "$NEW_TOPIC" ]]; then # Interactive mode echo "" echo " Create new o-o document" echo " ────────────────────────" echo "" read -p " Title: " OO_NEW_TITLE if [[ -z "$OO_NEW_TITLE" ]]; then echo " Error: Title is required." >&2 exit 1 fi echo "" read -p " Scope (what should this document cover?): " OO_NEW_SCOPE [[ -z "$OO_NEW_SCOPE" ]] && OO_NEW_SCOPE="$OO_NEW_TITLE" echo "" read -p " Audience [General readers]: " OO_NEW_AUDIENCE [[ -z "$OO_NEW_AUDIENCE" ]] && OO_NEW_AUDIENCE="General readers" read -p " Tone [Informative, well-researched, accessible]: " OO_NEW_TONE [[ -z "$OO_NEW_TONE" ]] && OO_NEW_TONE="Informative, well-researched, accessible" read -p " Budget USD [0.50]: " OO_NEW_BUDGET [[ -z "$OO_NEW_BUDGET" ]] && OO_NEW_BUDGET="0.50" echo "" OO_NEW_SLUG=$(slugify "$OO_NEW_TITLE") OO_NEW_PATH="${SELF_DIR}/${OO_NEW_SLUG}.o-o.html" if [[ -e "$OO_NEW_PATH" ]]; then echo " Error: File already exists: $OO_NEW_PATH" >&2 exit 1 fi echo " Creating: ${OO_NEW_SLUG}.o-o.html" generate_oo_file "$OO_NEW_PATH" "$OO_NEW_TITLE" "$OO_NEW_SCOPE" "$OO_NEW_SLUG" # Customize audience, tone, budget if not defaults OO_TMP="/tmp/oo_custom_$$" sed -e "s|\"audience\": \"General readers\"|\"audience\": \"${OO_NEW_AUDIENCE}\"|" \ -e "s|\"tone\": \"Informative, well-researched, accessible\"|\"tone\": \"${OO_NEW_TONE}\"|" \ -e "s|\"max_cost_usd\": 0.50|\"max_cost_usd\": ${OO_NEW_BUDGET}|" \ "$OO_NEW_PATH" > "$OO_TMP" && mv "$OO_TMP" "$OO_NEW_PATH" chmod +x "$OO_NEW_PATH" echo " Running first update..." echo "" bash "$OO_NEW_PATH" else create_new "$NEW_TOPIC" fi ;; update-all) if [[ "$IS_INDEX" -eq 0 ]]; then echo "o-o: --update-all is only available on index files." >&2 echo "o-o: Rename this file to index*.o-o.html to enable library management." >&2 exit 1 fi update_all "$FORCE" ;; sync) sync_section "$SYNC_SECTION" ;; show) show_contract ;; set) set_field "$SET_KEY" "$SET_VAL" ;; add) if [[ "$IS_INDEX" -eq 1 ]]; then echo "o-o: --add is for article files (modifies the research contract)." >&2 exit 1 fi add_to_array "$ARR_FIELD" "$ARR_VAL" ;; remove) if [[ "$IS_INDEX" -eq 1 ]]; then echo "o-o: --remove is for article files (modifies the research contract)." >&2 exit 1 fi remove_from_array "$ARR_FIELD" "$ARR_VAL" ;; help) show_help ;; "") if [[ "$IS_INDEX" -eq 1 ]]; then rebuild_index else # Article update: check freshness then dispatch if check_freshness; then exit 0 # still fresh, already printed message fi dispatch_update fi ;; esac # OO:SHELL:END exit 0