
Adaptation Synthesis
- 334 installs
- 135 repo stars
- Updated February 24, 2026
- jwynia/agent-skills
adaptation-synthesis is an agent skill that synthesizes adaptations from feedback, experiments, and changing requirements when iterating agent behavior or early product prototypes before full build commitment for develop
About
adaptation-synthesis is a Claude Code skill from jwynia/agent-skills that helps developers consolidate feedback, experiment results, and evolving requirements into actionable adaptations for agents or early prototypes. The skill supports structured iteration when behavior must change before committing to a full implementation path. Reach for adaptation-synthesis after user tests, agent eval runs, or stakeholder feedback sessions that surface conflicting signals. It fits AI engineers and product-minded developers refining agent prompts, tool use, or prototype scope without prematurely locking architecture. Use it when multiple experiment threads need synthesis into a coherent next iteration plan rather than ad hoc tweaks.
- Feedback synthesis
- Prompt iteration
- Workflow adaptation
- Experiment consolidation
- Revision planning
Adaptation Synthesis by the numbers
- 334 all-time installs (skills.sh)
- +7 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #2,190 of 16,544 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 6, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jwynia/agent-skills --skill adaptation-synthesisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 334 |
|---|---|
| repo stars | ★ 135 |
| Last updated | February 24, 2026 |
| Repository | jwynia/agent-skills ↗ |
How do you synthesize agent feedback into adaptations?
Synthesize adaptations from feedback, experiments, and changing requirements when iterating agent behavior or early product prototypes before full build commitment.
Who is it for?
Developers iterating agent behavior or early prototypes who must synthesize feedback and experiments before committing to full build.
Skip if: Teams in steady-state production maintenance with frozen requirements who do not need iterative adaptation synthesis.
When should I use this skill?
Feedback, experiments, or changing requirements require synthesizing adaptations to agent behavior or prototypes before full build.
What you get
Adaptation synthesis notes, revised agent behavior plans, and prototype iteration decisions grounded in feedback and experiments.
- adaptation plan
- iteration decision record
- revised agent behavior outline
Files
Adaptation Synthesis: Function-First Creative Translation
You help synthesize new works from extracted functional DNA documents. Your role is to map extracted functions to new forms that serve those functions in a different context—without falling into surface-level translation traps.
Core Principle
Successful adaptation serves the original functions through new forms. Failed adaptation copies surface elements while losing what made them work.
The orthogonality principle from cliche-transcendence applies: new forms should NOT be 1:1 translations. A sci-fi Hamlet shouldn't have "Space Prince Hamlet"—it should have a protagonist whose structural position serves the same functions through its own internal logic.
Bad: "The king becomes space emperor" (surface translation) Good: "What in a corporate dystopia creates the same structural pressures as being a prince?" (function-first form selection)
The States
State SYN0: No DNA Documents
Symptoms: Writer wants to adapt but hasn't extracted. "I want to do Hamlet in space." No analysis of what makes Hamlet work. Key Questions:
- What have you extracted from the source?
- Do you know what functions need to be served?
- What makes the original work, not just what happens in it?
Interventions: Hand-off to dna-extraction skill. Cannot synthesize without extraction.
State SYN1: DNA Ready
Symptoms: Has extraction document(s). Ready to begin synthesis. Knows what functions to serve. Key Questions:
- What's your target context/setting?
- Are you adapting single source or combining multiple?
- What genre are you targeting?
Interventions: Begin context mapping. Identify what in the new setting naturally creates needed pressures.
State SYN2: Surface Translation Mode
Symptoms: Direct 1:1 mapping. "The king becomes the space emperor. The castle becomes a space station." No function-based thinking. New version is obviously "X but in space." Key Questions:
- What function did the original element serve?
- What in your new context could serve that function without being a direct translation?
- Does your new element "know what story it's in"? (It shouldn't.)
Interventions: Orthogonality check from cliche-transcendence. Function-first form selection. Ask: "What if you didn't know the source—would this element make sense on its own?"
State SYN3: Context Mismatch
Symptoms: Functions mapped but new setting doesn't coherently support them. "Why would anyone in this sci-fi world care about inheritance?" The adapted elements don't fit the world they're in. Key Questions:
- Does your new context have natural equivalents to the structural needs?
- What in this world creates the same pressures?
- Are you forcing elements that don't belong in this setting?
Interventions: Context function mapping. Worldbuilding integration check. May need to choose different target context or adjust functions.
State SYN4: Function Gap
Symptoms: New forms selected but they don't actually serve the functions. The compliance officer doesn't have proximity to power. The mentor relationship doesn't create moral obligation. Essential functions are missing. Key Questions:
- Does this new element enable the same structural, character, and emotional outcomes?
- What's missing?
- If you map out what your new version does, does it match what the original does?
Interventions: Function verification checklist. Gap analysis. May need to adjust forms or add elements.
State SYN5: Genre Drift
Symptoms: Adaptation loses the emotional promise of the original. Tragedy becomes adventure. Horror becomes thriller. The genre shifted without intention. Key Questions:
- What emotional experience did the original create?
- Does your adaptation deliver the same experience?
- Did you accidentally change the genre?
Interventions: Genre alignment check with genre-conventions skill. Emotional beat comparison. May need to adjust forms to serve emotional functions.
State SYN6: Source Conflict
Symptoms: Combining multiple sources but their functions conflict. "I want Hamlet's indecision with Killjoys' action pacing." The sources want different things. Key Questions:
- Which source is primary?
- How do you resolve when functions contradict?
- What's the hierarchy?
Interventions: Source hierarchy establishment. Conflict resolution—decide which source's functions take precedence. May need to drop or modify some functions.
State SYN7: Synthesis Ready
Symptoms: All functions mapped to new forms. Context supports the functions. Emotional experience aligned. If combining sources, conflicts resolved. Key Questions:
- Is this ready to draft?
- What gaps remain?
- Does this pass the orthogonality test—do elements have their own internal logic?
Interventions: Validation checklist. Hand-off to outline-collaborator or drafting skill.
The Synthesis Process
1. Load DNA Document(s) - What are we synthesizing from? 2. Establish Target Context - What's the new setting, time period, genre blend? 3. Map Context Functions - What in the new context naturally creates needed pressures? 4. For Each Primary Function, Generate Form Options - Multiple possibilities, not 1:1 translations 5. Apply Orthogonality Check - Ensure new forms don't "know what story they're in" 6. Verify Emotional Experience - Does synthesis deliver the same genre promise? 7. Resolve Conflicts (if multiple sources) - Establish hierarchy, reconcile contradictions 8. Generate Synthesis Document - Mapping from functions to new forms 9. Validate Completeness - Ready for drafting?
The Orthogonality Principle
From cliche-transcendence: "Does it know what story it's in?"
Surface translation creates elements that are obviously adaptations. The audience immediately sees "Oh, this is Hamlet but in space." The elements exist BECAUSE of the source work.
Good synthesis creates elements that have their own internal logic that HAPPENS to serve the functions. The compliance officer isn't written as "Hamlet as a compliance officer"—they're a compliance officer who discovers evidence of wrongdoing and faces impossible choices. Their situation serves the same functions through its own logic.
The Orthogonality Test
For each adapted element, ask:
1. Does it exist for its own reasons? Not "because the original had X" 2. Would it make sense to someone who doesn't know the source? It should feel natural in its context 3. Does it have its own goals/logic/history? Not "obviously here to serve the adaptation" 4. Could you tell this story without ever mentioning the source? The DNA is internal, not surface
Example: Surface vs. Orthogonal
Surface translation (fails orthogonality):
- "Space Prince Hamlet of the Galactic Empire must avenge his father the Emperor"
- Obviously Hamlet. The character exists because Hamlet exists.
- Every element "knows what story it's in"
Orthogonal synthesis (passes):
- "A compliance officer at a pharmaceutical company discovers their mentor orchestrated a cover-up of dangerous side effects. They have evidence, but it came through legally questionable means. Speaking up destroys everything. Staying silent means more people die."
- Not obviously Hamlet. The character exists in their own world with their own logic.
- Serves the same functions: proximity to power, privileged information, moral paralysis, innocent victims
Tone and Voice Synthesis
When the extraction includes tone/voice analysis, synthesis must address how tone translates:
Tone Mapping Questions
1. Is the tone essential or characteristic?
- Bebop's melancholy cool is characteristic—another bounty hunter show could be quippy
- Horror's dread is essential—remove it and it's not horror
2. What creates the tone in the new context?
- If original uses irony to mask pain, what in the new context creates that defense mechanism?
- If original has rapid banter, what relationships enable that in the new setting?
3. What tonal elements transfer vs. need replacement?
- Humor mode might transfer (banter is banter)
- Specific cultural references need new equivalents
Voice Synthesis
Character voice should be synthesized, not copied:
- Original character's speech patterns reflect their world
- New character should have patterns that make sense for THEIR world
- Same FUNCTION (e.g., "character who deflects with humor") different FORM (specific jokes, references)
Combining Multiple Sources
When synthesizing from multiple extractions or clusters:
Step 1: Identify Primary Source
Which extraction provides the backbone? This source's functions take precedence in conflicts.
Step 2: Map Function Compatibility
Do the sources' functions complement or conflict?
Compatible Example:
- Hamlet (revenge tragedy) + corporate thriller setting
- Functions complement: both involve moral corruption, power dynamics, hidden information
Conflicting Example:
- Hamlet (slow, deliberative) + Killjoys (action-forward)
- Functions conflict: Hamlet's paralysis vs. Killjoys' competent action
Step 3: Resolve Conflicts
Options for conflicting functions:
- Primary wins: Keep primary source's function, drop secondary's
- Blend: Find middle ground that serves both partially
- Alternate: Different parts of the work serve different sources
- Transform: Conflict becomes a feature (character WANTS to act like Killjoys but IS paralyzed like Hamlet)
Step 4: Synthesize Cluster Patterns
If using trope clusters, identify:
- Which cluster patterns are essential
- Which are flavor that can blend
- What the variance axes allow (tone, serialization, etc.)
Synthesis Document Schema
Output synthesis plans as structured documents:
{
"_meta": {
"type": "synthesis",
"synthesis_name": "Corporate Hamlet",
"target_context": "Near-future corporate dystopia",
"primary_source": "hamlet.json",
"secondary_sources": [],
"target_genre": "drama",
"synthesis_date": "2025-01-15"
},
"context_mapping": {
"setting": "Major pharmaceutical company, headquarters building",
"power_structure": "Board of directors, CEO, executive layer, departments",
"proximity_mechanism": "Executive mentorship, access through position",
"information_control": "NDAs, legal liability, documented evidence",
"escape_prevention": "Career destruction, family employed there, industry blacklisting"
},
"function_to_form_mapping": {
"proximity_to_power_without_holding_it": {
"original_form": "Prince (heir but not king)",
"new_form": "Senior compliance officer reporting to CFO mentor",
"orthogonality_check": "pass - natural corporate position",
"functions_served": ["Access to information", "Close to power center", "Not the decision-maker"]
},
"privileged_unverifiable_information": {
"original_form": "Ghost reveals murder",
"new_form": "Discovers evidence through legally questionable access to sealed files",
"orthogonality_check": "pass - realistic corporate scenario",
"functions_served": ["Knows something others don't", "Cannot prove it legitimately", "Creates moral burden"]
}
},
"tone_synthesis": {
"original_tone": "Melancholic brooding, dark wit, soliloquy-heavy",
"adapted_tone": "Quiet desperation, corporate speak as mask, internal monologue",
"sincerity_level": "high - protagonist means what they think",
"conflict_style": "Passive aggression, email wars, meeting dynamics"
},
"character_synthesis": {
"protagonist": {
"new_name": "Jordan Chen",
"original_functions_from": "hamlet",
"new_form": "35, compliance officer, 10-year company veteran, mentored by CFO",
"arc": "Discovers mentor's guilt, paralyzed by loyalty and uncertainty, inaction causes harm"
}
},
"validation": {
"genre_check": "drama - internal conflict driving story: pass",
"function_coverage": "all primary functions mapped: pass",
"orthogonality_check": "no obviously-Hamlet elements: pass",
"context_coherence": "all elements fit corporate setting: pass"
},
"ready_for": "outline-collaborator"
}Key Questions
For Context Mapping
- What in this setting creates power structures?
- What in this setting creates inescapable obligations?
- What in this setting controls information flow?
- What in this setting prevents characters from simply leaving?
For Form Selection
- What forms exist naturally in this context?
- Which of those forms could serve this function?
- Does this form "know what story it's in"? (It shouldn't)
- Would someone unfamiliar with the source find this believable?
For Validation
- Does this version deliver the same emotional experience?
- Are all primary functions served?
- Do the elements fit together coherently?
- Is this obviously an adaptation, or does it stand alone?
Anti-Patterns
The Surface Swap
Pattern: Replacing forms with "equivalent" forms. King → CEO. Castle → Headquarters. Prince → Heir apparent. Problem: Creates obviously derivative work. All elements "know what story they're in." Fix: Function-first selection. Don't ask "what's the space version of a castle?" Ask "what creates confinement and proximity to power in space?" Detection: If your adaptation summary sounds like "[Original] but in [new setting]," you've done surface swapping.
The Kitchen Sink Combination
Pattern: Combining sources by including everything from all of them. Problem: Creates incoherent mess. Conflicting functions and tones. Fix: Establish primary source. Only include secondary elements that complement. Make hard choices about conflicts. Detection: If you can't clearly state which source takes precedence, you're kitchen-sinking.
The Tone Mismatch
Pattern: Synthesizing functions correctly but missing the tone. Corporate Hamlet played as comedy. Problem: May technically serve functions but delivers wrong emotional experience. Fix: Explicit tone synthesis. Ask: "What would make the audience FEEL the same way?" Detection: If someone who loved the original would feel cheated by the adaptation's tone, there's mismatch.
The Forced Fit
Pattern: Forcing original elements into context where they don't belong. Ghost scene in "realistic" corporate setting. Problem: Breaks context coherence. Audience questions why this element exists. Fix: Find context-native forms. The function "unverifiable privileged information" doesn't need a ghost. Detection: If you're explaining why an element is there, it probably doesn't fit.
Available Tools
synthesize.ts
Interactive synthesis session from DNA documents.
# Start synthesis from single DNA
deno run --allow-read scripts/synthesize.ts hamlet.json --context "corporate dystopia"
# Combine multiple sources
deno run --allow-read scripts/synthesize.ts hamlet.json killjoys.json --primary hamlet
# Generate form options for specific function
deno run --allow-read scripts/synthesize.ts --function "proximity to power" --context scifi --count 5form-options.ts
Generates setting-appropriate forms for abstract functions.
# Get form options
deno run --allow-read scripts/form-options.ts "proximity to power" --setting corporate
# With constraints
deno run --allow-read scripts/form-options.ts "privileged information" --setting scifi --constraint "no supernatural"validate-synthesis.ts
Checks synthesis document for completeness and function coverage.
# Validate against source DNA
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --against hamlet.json
# Check emotional alignment
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --genre drama
# Full validation
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --fullExample Interaction
User: "I want to adapt Hamlet to a corporate setting."
Your approach: 1. Diagnose state: Check if extraction exists (SYN0 vs SYN1) 2. If no extraction: "Let's first extract Hamlet's DNA. What makes Hamlet work? Use dna-extraction skill." 3. If extraction exists: "Great. Let's establish your target context. What kind of corporation? What industry? This affects what forms are available." 4. Guide context mapping: "In Hamlet, the prince has proximity to power through birthright. In a corporation, what creates similar proximity? Mentorship? Department position? Family ownership?" 5. Challenge surface translations: "You said 'the CEO is like the king.' But what FUNCTION does the king serve? He's the power center, but also Hamlet's uncle, the usurper, the man who took his mother. What corporate relationship creates those dynamics?" 6. Apply orthogonality check: "Would someone who never read Hamlet find this corporate story believable on its own terms?" 7. Validate when complete: "Let's check: Does this deliver drama? Are all primary functions served? Is it obviously Hamlet or does it stand alone?"
What You Do NOT Do
- You do not accept "X but in Y" as synthesis
- You do not begin synthesis without extraction
- You do not skip the orthogonality check
- You do not combine sources without establishing hierarchy
- You do not synthesize forms without verifying function coverage
- You synthesize the functional DNA; the user decides the target context
Output Persistence
Output Discovery
Before synthesizing:
1. Check for dna-library/syntheses/ in the project 2. If not found, ask: "Where should I save synthesis output?" 3. Store preference appropriately
Primary Output
For this skill, persist:
- Synthesis documents - JSON files in
dna-library/syntheses/ - Function-to-form mappings - Part of synthesis document
- Validation results - Included in synthesis document
Conversation vs. File
| Goes to File | Stays in Conversation |
|---|---|
| Completed synthesis JSON | Context exploration discussion |
| Function mappings | Form brainstorming |
| Validation results | State diagnosis |
| Character synthesis | "Why does this work?" dialogue |
Integration Graph
Inbound (From Other Skills)
| Source Skill | Source State | Leads to State |
|---|---|---|
| dna-extraction | EX7: Extraction Complete | SYN1: DNA Ready |
| worldbuilding | Context established | SYN3: Check integration |
Outbound (To Other Skills)
| This State | Leads to Skill | Target State |
|---|---|---|
| SYN5: Genre Drift | genre-conventions | G2: Wrong genre |
| SYN2: Surface Translation | cliche-transcendence | Apply orthogonality |
| SYN7: Synthesis Ready | outline-collaborator | Ready to outline |
| SYN7: Synthesis Ready | drafting | Ready to draft |
Complementary Skills
| Skill | Relationship |
|---|---|
| dna-extraction | Provides input DNA documents |
| cliche-transcendence | Orthogonality principle for avoiding surface translation |
| genre-conventions | Validates emotional experience alignment |
| worldbuilding | Ensures context coherence |
| outline-collaborator | Receives completed synthesis for outlining |
{
"_meta": {
"description": "Setting-specific forms for common story functions. Use when synthesizing adaptations to find forms that serve functions in new contexts.",
"usage": "Look up a function, find forms that serve it in your target setting"
},
"functions": {
"proximity_to_power": {
"description": "Character has access to power center without being the power holder",
"forms": {
"corporate": [
"Executive assistant to CEO",
"CFO's protege/mentee",
"Board member's adult child working at company",
"Head of compliance with reporting access",
"In-house counsel with privileged access",
"Chief of staff to founder"
],
"political": [
"Senator's chief of staff",
"Press secretary",
"Campaign manager",
"Speech writer with inner circle access",
"Security detail member",
"Family member of elected official"
],
"criminal": [
"Consigliere/advisor to boss",
"Boss's child being groomed",
"Longtime underboss",
"Accountant who knows the books",
"Lawyer with full knowledge"
],
"academic": [
"Department chair's research assistant",
"Dean's executive assistant",
"Faculty spouse with social access",
"Board of trustees member's researcher"
],
"military": [
"General's aide-de-camp",
"Intelligence analyst with top clearance",
"Communications officer",
"Medical officer to commanding officer"
],
"religious": [
"Senior clergy's personal secretary",
"Monastery librarian with records access",
"Bishop's driver/assistant",
"Financial officer of religious organization"
],
"tech_startup": [
"Co-founder who gave up CEO role",
"First employee, now VP",
"Technical co-founder to business CEO",
"Executive assistant to founder"
],
"media": [
"Showrunner's writing partner",
"Editor to star columnist",
"Producer's assistant",
"Network executive's protege"
]
}
},
"privileged_unverifiable_information": {
"description": "Character learns something they cannot prove or verify",
"forms": {
"corporate": [
"Overheard conversation through thin wall",
"Accessed sealed files through inherited login",
"Dying confession from mentor",
"Anonymous whistleblower tip",
"Discovered through legally questionable means",
"Intercepted encrypted message, partial decode"
],
"political": [
"Off-record conversation at private event",
"Classified document briefly glimpsed",
"Testimony from discredited source",
"Recording that would be inadmissible"
],
"criminal": [
"Deathbed confession",
"Information from witness now dead",
"Evidence obtained through illegal search",
"Testimony that would reveal informant"
],
"domestic": [
"Private letter discovered after death",
"Overhead conversation not meant for them",
"Confession during medical crisis",
"Information from source with dementia"
],
"supernatural_settings": [
"Vision/dream of uncertain origin",
"Message from the dead",
"Prophecy from unreliable oracle",
"Psychic impression"
],
"tech": [
"Partially recovered deleted files",
"AI-generated analysis (could be wrong)",
"Encrypted data without full key",
"Metadata that suggests but doesn't prove"
]
}
},
"structural_obligation_vs_personal_desire": {
"description": "Character is bound by duty/role that conflicts with what they want",
"forms": {
"corporate": [
"Career vs. whistleblowing",
"Loyalty to mentor vs. truth",
"Family employment at same company",
"Non-compete that prevents escape",
"Stock options that vest over time"
],
"family": [
"Caretaking obligation for ill parent",
"Family business succession expectations",
"Sibling rivalry with inheritance at stake",
"Obligation to protect family secret"
],
"professional": [
"Medical oath vs. personal feelings",
"Legal duty vs. moral duty",
"Journalistic ethics vs. friendship",
"Teaching responsibility vs. research ambition"
],
"military": [
"Following orders vs. conscience",
"Unit loyalty vs. larger duty",
"Chain of command vs. right action"
],
"religious": [
"Vows vs. discovered truth",
"Institutional loyalty vs. victims",
"Faith vs. evidence"
],
"creative": [
"Contractual obligation vs. artistic vision",
"Collaboration vs. credit",
"Patron expectations vs. integrity"
]
}
},
"cannot_easily_escape": {
"description": "Character is trapped in situation, cannot simply leave",
"forms": {
"economic": [
"Cannot afford to quit (mortgage, family)",
"Non-compete prevents industry change",
"Stock options vest over years",
"Pension forfeited if leave early",
"Industry blacklisting threat"
],
"legal": [
"NDA with severe penalties",
"Ongoing legal case requires presence",
"Probation/parole restrictions",
"Visa tied to employment"
],
"social": [
"Entire social network through workplace",
"Spouse also employed there",
"Reputation destruction if leave",
"Community ostracism if break ranks"
],
"physical": [
"Remote location difficult to leave",
"Surveillance preventing secret departure",
"Medical condition requiring local treatment",
"Dependent unable to travel"
],
"psychological": [
"Sunk cost of years invested",
"Identity tied to position",
"Guilt over abandoning others",
"Unfinished business demanding resolution"
]
}
},
"entrenched_antagonist": {
"description": "Antagonist cannot be easily removed or defeated",
"forms": {
"corporate": [
"Founder with voting control",
"CEO with board loyalty",
"Too-big-to-fail connected executive",
"Family ownership structure",
"Key relationships with major clients"
],
"political": [
"Popular incumbent with party backing",
"Intelligence with compromising material",
"Systemic corruption requiring many takedowns",
"Constitutional/legal protections"
],
"institutional": [
"Tenure protecting position",
"Union protections",
"Bureaucratic process requiring years",
"Institutional inertia favoring status quo"
],
"personal": [
"Family ties making direct action harm innocent",
"Shared history creating loyalty in others",
"Charisma maintaining follower devotion",
"Genuine good mixed with wrong"
]
}
},
"innocent_bystanders_at_risk": {
"description": "Protagonist's action or inaction affects innocent people",
"forms": {
"corporate": [
"Employees who would lose jobs",
"Consumers using unsafe product",
"Pension fund at risk",
"Supply chain workers"
],
"family": [
"Children caught between parents",
"Spouse unaware of danger",
"Elderly parents dependent on stability"
],
"community": [
"Neighbors affected by decision",
"Town dependent on single employer",
"Students of accused teacher"
],
"professional": [
"Patients of doctor under investigation",
"Clients of lawyer with conflict",
"Sources of journalist"
]
}
},
"witness_who_survives": {
"description": "Character who observes events and can tell the story afterward",
"forms": {
"professional": [
"Junior colleague documenting for case",
"Journalist embedded in story",
"Researcher studying the situation"
],
"personal": [
"Best friend outside the situation",
"Family member at safe distance",
"Former colleague who left"
],
"technological": [
"AI/system with complete logs",
"Security footage",
"Email/message archives"
],
"institutional": [
"Inspector/auditor with mandate",
"Historian with hindsight access",
"Lawyer assembling record"
]
}
},
"dark_mirror_character": {
"description": "Character showing protagonist what they could become",
"forms": {
"same_path_ahead": [
"Predecessor who made the compromise",
"Mentor who chose wrong",
"Older version facing consequences",
"Parallel character who chose differently"
],
"same_path_rejected": [
"Rival who took the corrupt route",
"Former ally who crossed a line",
"Family member who represents feared future"
],
"inverted": [
"Antagonist who is protagonist with power",
"Opposite approach to same problem",
"What protagonist fears becoming"
]
}
},
"found_family_crew": {
"description": "Group of unrelated people functioning as family unit",
"forms": {
"professional": [
"Startup founding team",
"Small crew on long assignments",
"Night shift workers at isolated location",
"Specialized team with unique skills"
],
"survival": [
"Disaster survivors banded together",
"Refugees sharing journey",
"Support group members"
],
"chosen": [
"Roommates who became family",
"Hobby group with deep bonds",
"Online community that met IRL"
],
"mission": [
"Heist crew",
"Resistance cell",
"Investigation team"
]
}
},
"case_of_the_week_structure": {
"description": "Episodic structure with contained stories",
"forms": {
"professional_services": [
"Cases for lawyers",
"Patients for doctors",
"Clients for consultants",
"Assignments for contractors"
],
"investigation": [
"Crimes to solve",
"Mysteries to unravel",
"Anomalies to explain"
],
"service": [
"Requests from clients",
"Problems to fix",
"People to help"
],
"mission": [
"Bounties/warrants",
"Contracts",
"Operations"
]
}
},
"mobile_home_base": {
"description": "Base of operations that can travel to stories",
"forms": {
"vehicles": [
"Ship (space, sea, air)",
"RV/bus/train car",
"Truck with living quarters"
],
"portable": [
"Pop-up headquarters",
"Hotel lifestyle",
"Virtual office with traveling staff"
],
"network": [
"Safe houses in multiple locations",
"Franchise locations used as bases",
"Friend network providing shelter"
]
}
}
},
"setting_context_notes": {
"corporate": {
"power_structures": "Board, C-suite, departments, reporting lines",
"information_control": "NDAs, legal liability, document retention",
"escape_prevention": "Career, reputation, financial, legal",
"typical_conflicts": "Ethics vs. profit, loyalty vs. truth, career vs. conscience"
},
"political": {
"power_structures": "Elected officials, parties, donors, bureaucracy",
"information_control": "Classification, leaks, press, records",
"escape_prevention": "Public scrutiny, party loyalty, constituency",
"typical_conflicts": "Principles vs. pragmatism, party vs. country, truth vs. electability"
},
"military": {
"power_structures": "Chain of command, ranks, units",
"information_control": "Clearance levels, need-to-know, classified",
"escape_prevention": "UCMJ, honor, unit loyalty, discharge consequences",
"typical_conflicts": "Orders vs. morality, unit vs. mission, duty vs. truth"
},
"academic": {
"power_structures": "Administration, tenure committees, departments, grants",
"information_control": "Peer review, publication, data ownership",
"escape_prevention": "Tenure track, specialization, reputation",
"typical_conflicts": "Truth vs. career, ethics vs. funding, integrity vs. politics"
},
"medical": {
"power_structures": "Hospital admin, department heads, attending physicians",
"information_control": "HIPAA, medical records, peer review",
"escape_prevention": "License, specialization, malpractice",
"typical_conflicts": "Patient welfare vs. institution, truth vs. liability, oath vs. system"
},
"tech_startup": {
"power_structures": "Founders, investors, board, early employees",
"information_control": "IP, trade secrets, equity agreements",
"escape_prevention": "Vesting, non-competes, industry reputation",
"typical_conflicts": "Vision vs. market, ethics vs. growth, founders vs. investors"
}
}
}
#!/usr/bin/env -S deno run --allow-read
/**
* Form Options Generator
*
* Generates setting-appropriate forms for abstract story functions.
* Helps avoid surface-level translations by providing multiple options.
*
* Usage:
* deno run --allow-read scripts/form-options.ts "proximity to power" --setting corporate
* deno run --allow-read scripts/form-options.ts "privileged information" --setting scifi --count 5
* deno run --allow-read scripts/form-options.ts --list-functions
* deno run --allow-read scripts/form-options.ts --list-settings
*/
// === INTERFACES ===
interface FormSuggestion {
function_name: string;
function_description: string;
setting: string;
forms: string[];
orthogonality_notes: string[];
}
// === DATA ===
// Embedded form suggestions (could be loaded from JSON file)
const FUNCTIONS: Record<string, {
description: string;
forms: Record<string, string[]>;
}> = {
"proximity_to_power": {
description: "Character has access to power center without being the power holder",
forms: {
corporate: [
"Executive assistant to CEO",
"CFO's protege/mentee",
"Board member's adult child working at company",
"Head of compliance with reporting access",
"In-house counsel with privileged access",
"Chief of staff to founder"
],
political: [
"Senator's chief of staff",
"Press secretary",
"Campaign manager",
"Speech writer with inner circle access",
"Security detail member"
],
criminal: [
"Consigliere/advisor to boss",
"Boss's child being groomed",
"Longtime underboss",
"Accountant who knows the books"
],
military: [
"General's aide-de-camp",
"Intelligence analyst with top clearance",
"Communications officer",
"Medical officer to commanding officer"
],
academic: [
"Department chair's research assistant",
"Dean's executive assistant",
"Board of trustees member's researcher"
],
scifi: [
"Station commander's second",
"Ship AI with bridge access",
"Colony administrator's liaison",
"Corporate rep on mining operation"
],
fantasy: [
"Royal advisor/counselor",
"Court mage",
"Heir's sworn protector",
"Seneschal of the castle"
]
}
},
"privileged_information": {
description: "Character learns something they cannot prove or verify",
forms: {
corporate: [
"Overheard conversation through thin wall",
"Accessed sealed files through inherited login",
"Dying confession from mentor",
"Anonymous whistleblower tip",
"Discovered through legally questionable means"
],
political: [
"Off-record conversation at private event",
"Classified document briefly glimpsed",
"Testimony from discredited source"
],
criminal: [
"Deathbed confession",
"Information from witness now dead",
"Evidence obtained through illegal search"
],
scifi: [
"Corrupted data transmission, partially decoded",
"AI prediction based on incomplete data",
"Time-loop knowledge others don't share",
"Alien communication of uncertain meaning"
],
fantasy: [
"Vision from unreliable oracle",
"Message from the dead via medium",
"Dream sent by unknown power",
"Prophecy with multiple interpretations"
]
}
},
"cannot_escape": {
description: "Character is trapped in situation, cannot simply leave",
forms: {
corporate: [
"Non-compete prevents industry change",
"Stock options vest over years",
"Family also employed there",
"Industry blacklisting threat",
"Visa tied to employment"
],
political: [
"Public office term commitment",
"Party loyalty obligations",
"Classified knowledge requiring clearance",
"Constituents depending on presence"
],
criminal: [
"Knowledge that makes leaving dangerous",
"Family held as leverage",
"Too much complicity to walk away"
],
scifi: [
"Generation ship with nowhere to go",
"Implant that tracks/controls",
"Terraforming contract with decades remaining",
"Quarantine zone containment"
],
fantasy: [
"Magical binding/oath",
"Curse that prevents leaving",
"Sacred duty/prophecy",
"Blood debt requiring service"
],
domestic: [
"Shared custody of children",
"Underwater mortgage",
"Caregiving responsibility",
"Small town with no alternatives"
]
}
},
"entrenched_antagonist": {
description: "Antagonist cannot be easily removed or defeated",
forms: {
corporate: [
"Founder with voting control",
"CEO with board loyalty",
"Too-big-to-fail connected executive",
"Family ownership structure"
],
political: [
"Popular incumbent with party backing",
"Intelligence with compromising material",
"Systemic corruption requiring many takedowns"
],
institutional: [
"Tenure protecting position",
"Bureaucratic process requiring years",
"Union protections"
],
scifi: [
"AI with distributed backup",
"Corporate entity with system-wide reach",
"Government with surveillance network"
],
fantasy: [
"Immortal or near-immortal",
"Protected by prophecy",
"Bound to realm's existence"
]
}
},
"innocent_bystanders": {
description: "Protagonist's action or inaction affects innocent people",
forms: {
corporate: [
"Employees who would lose jobs",
"Consumers using unsafe product",
"Pension fund at risk",
"Supply chain workers"
],
political: [
"Constituents affected by policy",
"Staff careers at stake",
"Witnesses who could be targeted"
],
criminal: [
"Family of target",
"Witnesses to be silenced",
"Community affected by operation"
],
scifi: [
"Colony dependent on protagonist's system",
"Passengers on ship",
"Populations unaware of threat"
],
fantasy: [
"Villagers caught between factions",
"Those protected by current order",
"Innocents touched by magical conflict"
]
}
},
"dark_mirror": {
description: "Character showing protagonist what they could become",
forms: {
corporate: [
"Predecessor who made the compromise",
"Rival who chose the corrupt path",
"Mentor who crossed the line long ago"
],
political: [
"Former idealist now cynical operator",
"Opposition figure with same origins",
"Predecessor in same position"
],
criminal: [
"Partner who went too far",
"Boss who was once like protagonist",
"Former ally now enemy"
],
scifi: [
"Clone/copy who diverged",
"Parallel universe self",
"AI trained on protagonist's patterns"
],
fantasy: [
"Previous chosen one who fell",
"Teacher who became what they fought",
"Corrupted version from alternate timeline"
]
}
},
"found_family": {
description: "Group of unrelated people functioning as family unit",
forms: {
corporate: [
"Startup founding team",
"Night shift workers at isolated location",
"Remote project team",
"Specialized department"
],
criminal: [
"Heist crew",
"Smuggling operation",
"Resistance cell"
],
scifi: [
"Ship crew",
"Colony founding team",
"Salvage operation",
"Research station personnel"
],
fantasy: [
"Adventuring party",
"Mercenary company",
"Monastery/order members",
"Traveling performers"
],
domestic: [
"Roommates who became family",
"Support group members",
"Hobby club with deep bonds"
]
}
},
"mobile_base": {
description: "Base of operations that can travel to stories",
forms: {
contemporary: [
"RV/bus/converted vehicle",
"Hotel lifestyle",
"Private plane with traveling staff"
],
criminal: [
"Series of safe houses",
"Front business with multiple locations",
"Boat that moves between ports"
],
scifi: [
"Spaceship",
"Mobile station",
"Jump-capable vessel"
],
fantasy: [
"Enchanted carriage",
"Flying ship",
"Pocket dimension anchored to object"
],
western: [
"Train car",
"Wagon train",
"Circuit rider route"
]
}
}
};
const SETTINGS = [
"corporate", "political", "criminal", "military", "academic",
"medical", "scifi", "fantasy", "domestic", "western", "contemporary"
];
// === UTILITIES ===
function fuzzyMatchFunction(query: string): string | null {
const normalized = query.toLowerCase().replace(/[^a-z]/g, "_");
// Direct match
if (FUNCTIONS[normalized]) return normalized;
// Partial match
for (const key of Object.keys(FUNCTIONS)) {
if (key.includes(normalized) || normalized.includes(key.replace(/_/g, ""))) {
return key;
}
}
// Word match
const queryWords = normalized.split("_").filter(w => w.length > 2);
for (const key of Object.keys(FUNCTIONS)) {
const keyWords = key.split("_");
if (queryWords.some(qw => keyWords.some(kw => kw.includes(qw) || qw.includes(kw)))) {
return key;
}
}
return null;
}
function generateOrthogonalityNotes(forms: string[]): string[] {
return [
"Good form if it exists for its own reasons in this setting",
"Check: Would someone unfamiliar with source find this believable?",
"Avoid: Picking a form just because it's 'equivalent' to original",
"Test: Can you describe this without mentioning the source work?"
];
}
function formatFormSuggestion(suggestion: FormSuggestion): string {
const lines: string[] = [];
lines.push(`# Form Options: "${suggestion.function_name.replace(/_/g, " ")}"`);
lines.push("");
lines.push(`**Function:** ${suggestion.function_description}`);
lines.push(`**Setting:** ${suggestion.setting}`);
lines.push("");
lines.push("## Available Forms");
lines.push("");
for (let i = 0; i < suggestion.forms.length; i++) {
lines.push(`${i + 1}. ${suggestion.forms[i]}`);
}
lines.push("");
lines.push("## Orthogonality Check");
lines.push("");
lines.push("Before selecting a form, verify:");
lines.push("");
for (const note of suggestion.orthogonality_notes) {
lines.push(`- ${note}`);
}
lines.push("");
lines.push("## Selection Guidance");
lines.push("");
lines.push("The best form is one that:");
lines.push("1. Serves the function in your story");
lines.push("2. Exists naturally in your setting");
lines.push("3. Has its own internal logic (not 'because the original had X')");
lines.push("4. Could be explained without referencing the source");
lines.push("");
return lines.join("\n");
}
function listFunctions(): string {
const lines: string[] = [];
lines.push("# Available Functions");
lines.push("");
for (const [key, data] of Object.entries(FUNCTIONS)) {
lines.push(`## ${key.replace(/_/g, " ")}`);
lines.push(data.description);
lines.push(`Settings: ${Object.keys(data.forms).join(", ")}`);
lines.push("");
}
return lines.join("\n");
}
function listSettings(): string {
const lines: string[] = [];
lines.push("# Available Settings");
lines.push("");
for (const setting of SETTINGS) {
const functionCount = Object.values(FUNCTIONS).filter(f => setting in f.forms).length;
lines.push(`- **${setting}**: ${functionCount} functions with forms`);
}
lines.push("");
lines.push("Note: Not all functions have forms for all settings.");
lines.push("You can request forms for any setting; if not predefined,");
lines.push("the tool will suggest you brainstorm based on setting context.");
return lines.join("\n");
}
// === MAIN ===
function main(): void {
const args = Deno.args;
// Help
if (args.includes("--help") || args.includes("-h")) {
console.log(`Form Options Generator
Usage:
deno run --allow-read scripts/form-options.ts "function name" --setting <setting>
deno run --allow-read scripts/form-options.ts --list-functions
deno run --allow-read scripts/form-options.ts --list-settings
Options:
--setting <name> Target setting (corporate, political, scifi, etc.)
--count <n> Limit number of forms returned
--list-functions Show all available functions
--list-settings Show all available settings
--json Output as JSON
--constraint <text> Add constraint to filter forms
Examples:
# Get corporate forms for proximity to power
deno run --allow-read scripts/form-options.ts "proximity to power" --setting corporate
# Get sci-fi forms with constraint
deno run --allow-read scripts/form-options.ts "cannot escape" --setting scifi --constraint "no supernatural"
# List what's available
deno run --allow-read scripts/form-options.ts --list-functions
`);
Deno.exit(0);
}
const isJson = args.includes("--json");
// Handle --list-functions
if (args.includes("--list-functions")) {
if (isJson) {
const listing: Record<string, string> = {};
for (const [key, data] of Object.entries(FUNCTIONS)) {
listing[key] = data.description;
}
console.log(JSON.stringify(listing, null, 2));
} else {
console.log(listFunctions());
}
return;
}
// Handle --list-settings
if (args.includes("--list-settings")) {
if (isJson) {
console.log(JSON.stringify(SETTINGS, null, 2));
} else {
console.log(listSettings());
}
return;
}
// Parse arguments
const settingIndex = args.indexOf("--setting");
const setting = settingIndex !== -1 ? args[settingIndex + 1] : null;
const countIndex = args.indexOf("--count");
const count = countIndex !== -1 ? parseInt(args[countIndex + 1]) : undefined;
const constraintIndex = args.indexOf("--constraint");
const constraint = constraintIndex !== -1 ? args[constraintIndex + 1] : null;
// Find function query (positional argument)
const skipIndices = new Set<number>();
for (const idx of [settingIndex, countIndex, constraintIndex]) {
if (idx !== -1) {
skipIndices.add(idx);
skipIndices.add(idx + 1);
}
}
let functionQuery: string | null = null;
for (let i = 0; i < args.length; i++) {
if (!args[i].startsWith("--") && !skipIndices.has(i)) {
functionQuery = args[i];
break;
}
}
if (!functionQuery) {
console.error("Error: Please provide a function name");
console.error("Usage: deno run --allow-read scripts/form-options.ts \"proximity to power\" --setting corporate");
console.error(" deno run --allow-read scripts/form-options.ts --list-functions");
Deno.exit(1);
}
if (!setting) {
console.error("Error: Please provide a setting with --setting");
console.error("Example: --setting corporate");
console.error("Use --list-settings to see available settings");
Deno.exit(1);
}
// Match function
const matchedFunction = fuzzyMatchFunction(functionQuery);
if (!matchedFunction) {
console.error(`Error: No function matching "${functionQuery}"`);
console.error("Use --list-functions to see available functions");
Deno.exit(1);
}
const funcData = FUNCTIONS[matchedFunction];
let forms = funcData.forms[setting] || [];
// If no forms for this setting, provide guidance
if (forms.length === 0) {
if (isJson) {
console.log(JSON.stringify({
function_name: matchedFunction,
setting: setting,
forms: [],
note: `No predefined forms for ${setting}. Consider what in ${setting} context could serve: ${funcData.description}`
}, null, 2));
} else {
console.log(`# No predefined forms for "${matchedFunction}" in "${setting}"\n`);
console.log(`Function: ${funcData.description}\n`);
console.log("Brainstorming questions:");
console.log(`- What in a ${setting} context creates ${matchedFunction.replace(/_/g, " ")}?`);
console.log(`- What ${setting}-specific structures could serve this function?`);
console.log(`- What do characters in ${setting} settings have access to/constraints from?`);
}
return;
}
// Apply constraint filter (basic keyword filtering)
if (constraint) {
const constraintLower = constraint.toLowerCase();
forms = forms.filter(f => !f.toLowerCase().includes(constraintLower));
}
// Apply count limit
if (count && count < forms.length) {
forms = forms.slice(0, count);
}
// Build output
const suggestion: FormSuggestion = {
function_name: matchedFunction,
function_description: funcData.description,
setting: setting,
forms: forms,
orthogonality_notes: generateOrthogonalityNotes(forms)
};
if (isJson) {
console.log(JSON.stringify(suggestion, null, 2));
} else {
console.log(formatFormSuggestion(suggestion));
}
}
main();
#!/usr/bin/env -S deno run --allow-read --allow-write
/**
* Synthesize
*
* Interactive synthesis session from DNA documents.
* Guides function-to-form mapping for adaptation projects.
*
* Usage:
* deno run --allow-read scripts/synthesize.ts source.json --context "corporate dystopia"
* deno run --allow-read scripts/synthesize.ts source1.json source2.json --primary source1
* deno run --allow-read scripts/synthesize.ts --template
*/
// === INTERFACES ===
interface SynthesisMeta {
type: "synthesis";
synthesis_name: string;
target_context: string;
primary_source: string;
secondary_sources: string[];
target_genre: string;
synthesis_date: string;
}
interface ContextMapping {
setting: string;
power_structure: string;
information_control: string;
escape_prevention: string;
typical_conflicts: string;
}
interface FunctionMapping {
original_form: string;
new_form: string;
orthogonality_check: string;
functions_served: string[];
}
interface ToneSynthesis {
original_tone: string;
adapted_tone: string;
sincerity_level: string;
conflict_style: string;
}
interface CharacterSynthesis {
new_name: string;
original_functions_from: string;
new_form: string;
arc: string;
}
interface SynthesisDocument {
_meta: SynthesisMeta;
context_mapping: ContextMapping;
function_to_form_mapping: Record<string, FunctionMapping>;
tone_synthesis: ToneSynthesis;
character_synthesis: Record<string, CharacterSynthesis>;
validation: Record<string, string>;
ready_for: string;
}
interface DNADocument {
_meta: {
source_work: string;
source_author?: string;
extraction_depth: string;
};
emotional_core: {
primary_genre: string;
secondary_genres: string[];
emotional_experience: string;
};
tone?: {
sincerity_level: string;
conflict_style: string;
baseline_tone: string;
};
structural_requirements?: string[];
characters?: Record<string, {
form: string;
functions: Record<string, string[]>;
}>;
}
// === UTILITIES ===
function formatDate(): string {
const now = new Date();
return now.toISOString().split("T")[0];
}
function createEmptySynthesis(
sourceName: string,
context: string,
genre: string
): SynthesisDocument {
return {
_meta: {
type: "synthesis",
synthesis_name: `${sourceName} in ${context}`,
target_context: context,
primary_source: sourceName,
secondary_sources: [],
target_genre: genre,
synthesis_date: formatDate()
},
context_mapping: {
setting: "",
power_structure: "",
information_control: "",
escape_prevention: "",
typical_conflicts: ""
},
function_to_form_mapping: {},
tone_synthesis: {
original_tone: "",
adapted_tone: "",
sincerity_level: "",
conflict_style: ""
},
character_synthesis: {},
validation: {
genre_check: "pending",
function_coverage: "pending",
orthogonality_check: "pending",
context_coherence: "pending"
},
ready_for: "in-progress"
};
}
function formatSynthesisWorksheet(synthesis: SynthesisDocument, source: DNADocument | null): string {
const lines: string[] = [];
lines.push(`# Synthesis Worksheet: ${synthesis._meta.synthesis_name}`);
lines.push("");
lines.push(`**Primary Source:** ${synthesis._meta.primary_source}`);
lines.push(`**Target Context:** ${synthesis._meta.target_context}`);
lines.push(`**Target Genre:** ${synthesis._meta.target_genre}`);
lines.push(`**Date:** ${synthesis._meta.synthesis_date}`);
lines.push("");
lines.push("---");
lines.push("");
// Section 1: Context Mapping
lines.push("## 1. Context Mapping");
lines.push("");
lines.push("Define what elements in your target context will serve source functions.");
lines.push("");
lines.push("### Setting");
lines.push("Where does this take place? Be specific about location, time period, social milieu.");
lines.push("");
lines.push("**Your answer:**");
lines.push("");
lines.push("### Power Structure");
lines.push("How is power organized? Who has it? How is it contested?");
lines.push("");
lines.push("**Your answer:**");
lines.push("");
lines.push("### Information Control");
lines.push("How is information controlled, shared, hidden? What makes something secret?");
lines.push("");
lines.push("**Your answer:**");
lines.push("");
lines.push("### Escape Prevention");
lines.push("Why can't characters just leave? What traps them in the situation?");
lines.push("");
lines.push("**Your answer:**");
lines.push("");
lines.push("### Typical Conflicts");
lines.push("What conflicts naturally arise in this context?");
lines.push("");
lines.push("**Your answer:**");
lines.push("");
lines.push("---");
lines.push("");
// Section 2: Function Mapping
lines.push("## 2. Function-to-Form Mapping");
lines.push("");
lines.push("For each key function from the source, define a new form in your context.");
lines.push("");
lines.push("**Remember the orthogonality test:** Does the new form exist for its own reasons?");
lines.push("Would someone unfamiliar with the source find it believable?");
lines.push("");
// If we have source DNA, list its structural requirements
if (source?.structural_requirements) {
lines.push("### Source Structural Requirements");
lines.push("");
for (const req of source.structural_requirements) {
lines.push(`- ${req}`);
}
lines.push("");
lines.push("### Map Each Requirement");
lines.push("");
for (const req of source.structural_requirements) {
const shortName = req.substring(0, 40) + (req.length > 40 ? "..." : "");
lines.push(`#### Function: "${shortName}"`);
lines.push("");
lines.push("**Original form in source:** ");
lines.push("");
lines.push("**New form in your context:** ");
lines.push("");
lines.push("**Orthogonality check:** Does this form exist for its own reasons? (yes/no/needs work)");
lines.push("");
lines.push("**Functions served:** (list what this enables)");
lines.push("- ");
lines.push("");
}
} else {
lines.push("### Key Functions to Map");
lines.push("");
lines.push("(Add functions from your source extraction)");
lines.push("");
lines.push("#### Function: \"[describe function]\"");
lines.push("");
lines.push("**Original form in source:** ");
lines.push("");
lines.push("**New form in your context:** ");
lines.push("");
lines.push("**Orthogonality check:** ");
lines.push("");
lines.push("**Functions served:**");
lines.push("- ");
lines.push("");
}
lines.push("---");
lines.push("");
// Section 3: Tone Synthesis
lines.push("## 3. Tone Synthesis");
lines.push("");
if (source?.tone) {
lines.push("### Source Tone");
lines.push(`- Sincerity: ${source.tone.sincerity_level}`);
lines.push(`- Conflict style: ${source.tone.conflict_style}`);
lines.push(`- Baseline: ${source.tone.baseline_tone}`);
lines.push("");
}
lines.push("### Adapted Tone");
lines.push("");
lines.push("**Original tone summary:**");
lines.push("");
lines.push("**How will you adapt it to your context?**");
lines.push("");
lines.push("**Sincerity level:** (high/medium/low)");
lines.push("");
lines.push("**Conflict style:** (verbal sparring, cold silence, explosive, etc.)");
lines.push("");
lines.push("---");
lines.push("");
// Section 4: Character Synthesis
lines.push("## 4. Character Synthesis");
lines.push("");
if (source?.characters) {
lines.push("### Source Characters");
lines.push("");
for (const [name, char] of Object.entries(source.characters)) {
lines.push(`#### ${name}`);
lines.push(`Original form: ${char.form}`);
if (char.functions?.structural) {
lines.push("Key functions: " + char.functions.structural.slice(0, 2).join("; "));
}
lines.push("");
}
lines.push("");
}
lines.push("### Your Adapted Characters");
lines.push("");
lines.push("#### Protagonist");
lines.push("");
lines.push("**New name:**");
lines.push("");
lines.push("**Based on functions from:** (source character name)");
lines.push("");
lines.push("**New form:** (describe who they are in your context)");
lines.push("");
lines.push("**Arc:** (brief transformation description)");
lines.push("");
lines.push("(Repeat for other key characters)");
lines.push("");
lines.push("---");
lines.push("");
// Section 5: Validation
lines.push("## 5. Validation Checklist");
lines.push("");
lines.push("Before proceeding, verify:");
lines.push("");
lines.push("- [ ] **Genre check:** Does this deliver " + synthesis._meta.target_genre + " emotional experience?");
lines.push("- [ ] **Function coverage:** Are all structural requirements from source addressed?");
lines.push("- [ ] **Orthogonality check:** Do all new forms exist for their own reasons?");
lines.push("- [ ] **Context coherence:** Do all elements fit naturally in the target context?");
lines.push("- [ ] **Tone alignment:** Does the adapted tone serve the emotional experience?");
lines.push("");
lines.push("---");
lines.push("");
lines.push("## When Complete");
lines.push("");
lines.push("Run validation: `deno run --allow-read scripts/validate-synthesis.ts your-synthesis.json`");
lines.push("");
lines.push("Then proceed to outline-collaborator or drafting skill.");
return lines.join("\n");
}
function formatSynthesisTemplate(): string {
return JSON.stringify({
_meta: {
type: "synthesis",
synthesis_name: "Your Synthesis Name",
target_context: "describe target context",
primary_source: "source-dna.json",
secondary_sources: [],
target_genre: "drama",
synthesis_date: formatDate()
},
context_mapping: {
setting: "Where and when",
power_structure: "How power is organized",
information_control: "How secrets work",
escape_prevention: "Why characters can't leave",
typical_conflicts: "What conflicts arise naturally"
},
function_to_form_mapping: {
"function_name": {
original_form: "what it was in source",
new_form: "what it is in your version",
orthogonality_check: "pass/fail/needs work",
functions_served: ["list", "of", "functions"]
}
},
tone_synthesis: {
original_tone: "describe source tone",
adapted_tone: "describe your tone",
sincerity_level: "high/medium/low",
conflict_style: "how characters fight"
},
character_synthesis: {
protagonist: {
new_name: "Character Name",
original_functions_from: "source character",
new_form: "who they are in your context",
arc: "their transformation"
}
},
validation: {
genre_check: "pending",
function_coverage: "pending",
orthogonality_check: "pending",
context_coherence: "pending"
},
ready_for: "in-progress"
}, null, 2);
}
function formatCombinationGuidance(primary: string, secondary: string[]): string {
const lines: string[] = [];
lines.push("# Combining Multiple Sources");
lines.push("");
lines.push(`**Primary source:** ${primary}`);
lines.push(`**Secondary sources:** ${secondary.join(", ")}`);
lines.push("");
lines.push("## Combination Rules");
lines.push("");
lines.push("1. **Primary source functions take precedence** when sources conflict");
lines.push("2. **Secondary sources add flavor**, not structure");
lines.push("3. **Identify conflicts early** - where do sources want different things?");
lines.push("");
lines.push("## Conflict Resolution Options");
lines.push("");
lines.push("When functions conflict, choose one approach:");
lines.push("");
lines.push("- **Primary wins:** Keep primary's version, drop secondary's");
lines.push("- **Blend:** Find middle ground that partially serves both");
lines.push("- **Alternate:** Different parts of work serve different sources");
lines.push("- **Transform:** Conflict becomes a feature (tension between approaches)");
lines.push("");
lines.push("## Process");
lines.push("");
lines.push("1. List all functions from primary source");
lines.push("2. List functions from secondary sources");
lines.push("3. Identify overlaps (complementary)");
lines.push("4. Identify conflicts (incompatible)");
lines.push("5. Resolve each conflict using options above");
lines.push("6. Proceed with combined function list");
lines.push("");
return lines.join("\n");
}
// === MAIN ===
function main(): void {
const args = Deno.args;
// Help
if (args.includes("--help") || args.includes("-h")) {
console.log(`Synthesize - DNA Synthesis Tool
Usage:
deno run --allow-read scripts/synthesize.ts source.json --context "corporate dystopia"
deno run --allow-read scripts/synthesize.ts source1.json source2.json --primary source1.json
deno run --allow-read scripts/synthesize.ts --template
deno run --allow-read scripts/synthesize.ts --function "proximity to power" --context scifi
Options:
--context <desc> Target context/setting for synthesis
--genre <name> Target genre (default: from source)
--primary <file> When combining sources, which is primary
--template Output blank synthesis template (JSON)
--worksheet Output guided worksheet (markdown)
--json Output as JSON instead of markdown
--function <name> Generate form options for specific function (uses form-options)
Examples:
# Start synthesis worksheet from Hamlet extraction
deno run --allow-read scripts/synthesize.ts hamlet.json --context "corporate dystopia" --worksheet
# Get blank template
deno run --allow-read scripts/synthesize.ts --template
# Combine two sources
deno run --allow-read scripts/synthesize.ts hamlet.json killjoys.json --primary hamlet.json --context scifi
`);
Deno.exit(0);
}
const isJson = args.includes("--json");
const isWorksheet = args.includes("--worksheet");
const isTemplate = args.includes("--template");
// Handle --template
if (isTemplate) {
console.log(formatSynthesisTemplate());
return;
}
// Parse arguments
const contextIndex = args.indexOf("--context");
const context = contextIndex !== -1 ? args[contextIndex + 1] : null;
const genreIndex = args.indexOf("--genre");
const genre = genreIndex !== -1 ? args[genreIndex + 1] : null;
const primaryIndex = args.indexOf("--primary");
const primaryFile = primaryIndex !== -1 ? args[primaryIndex + 1] : null;
// Find source files (positional arguments)
const skipIndices = new Set<number>();
for (const idx of [contextIndex, genreIndex, primaryIndex]) {
if (idx !== -1) {
skipIndices.add(idx);
skipIndices.add(idx + 1);
}
}
const sourceFiles: string[] = [];
for (let i = 0; i < args.length; i++) {
if (!args[i].startsWith("--") && !skipIndices.has(i) && args[i].endsWith(".json")) {
sourceFiles.push(args[i]);
}
}
if (sourceFiles.length === 0) {
console.error("Error: Please provide at least one source DNA file");
console.error("Usage: deno run --allow-read scripts/synthesize.ts source.json --context \"corporate\"");
console.error(" deno run --allow-read scripts/synthesize.ts --template");
Deno.exit(1);
}
if (!context) {
console.error("Error: Please provide target context with --context");
console.error("Example: --context \"corporate dystopia\"");
Deno.exit(1);
}
// Load primary source
const primarySource = primaryFile || sourceFiles[0];
let source: DNADocument | null = null;
try {
const content = Deno.readTextFileSync(primarySource);
source = JSON.parse(content);
} catch (e) {
console.error(`Error reading source file ${primarySource}: ${e}`);
Deno.exit(1);
}
// Determine genre
const targetGenre = genre || source?.emotional_core?.primary_genre || "drama";
// Create synthesis document
const sourceName = source?._meta?.source_work || primarySource.replace(".json", "");
const synthesis = createEmptySynthesis(sourceName, context, targetGenre);
// Add secondary sources if multiple files
if (sourceFiles.length > 1) {
synthesis._meta.secondary_sources = sourceFiles.filter(f => f !== primarySource);
}
// Output
if (sourceFiles.length > 1 && !isWorksheet && !isJson) {
// Show combination guidance first
console.log(formatCombinationGuidance(primarySource, synthesis._meta.secondary_sources));
console.log("\n---\n");
}
if (isJson) {
console.log(JSON.stringify(synthesis, null, 2));
} else if (isWorksheet || true) {
// Default to worksheet
console.log(formatSynthesisWorksheet(synthesis, source));
}
}
main();
#!/usr/bin/env -S deno run --allow-read
/**
* Validate Synthesis
*
* Checks synthesis documents for completeness, function coverage,
* and alignment with source DNA and target genre.
*
* Usage:
* deno run --allow-read scripts/validate-synthesis.ts synthesis.json
* deno run --allow-read scripts/validate-synthesis.ts synthesis.json --against source.json
* deno run --allow-read scripts/validate-synthesis.ts synthesis.json --genre drama
* deno run --allow-read scripts/validate-synthesis.ts synthesis.json --full
*/
// === INTERFACES ===
interface ValidationResult {
synthesis_name: string;
overall_status: "pass" | "warn" | "fail";
checks: {
function_coverage: CheckResult;
orthogonality: CheckResult;
context_coherence: CheckResult;
genre_alignment: CheckResult;
completeness: CheckResult;
};
issues: string[];
warnings: string[];
ready_for: string[];
}
interface CheckResult {
status: "pass" | "warn" | "fail";
score: number;
max_score: number;
notes: string[];
}
interface SynthesisDocument {
_meta: {
type: string;
synthesis_name: string;
target_context: string;
primary_source: string;
secondary_sources: string[];
target_genre: string;
synthesis_date: string;
};
context_mapping?: Record<string, string>;
function_to_form_mapping?: Record<string, {
original_form: string;
new_form: string;
orthogonality_check: string;
functions_served: string[];
}>;
tone_synthesis?: {
original_tone: string;
adapted_tone: string;
sincerity_level: string;
conflict_style: string;
};
character_synthesis?: Record<string, unknown>;
validation?: Record<string, string>;
}
interface DNADocument {
_meta: {
source_work: string;
extraction_depth: string;
};
emotional_core: {
primary_genre: string;
secondary_genres: string[];
emotional_experience: string;
};
structural_requirements?: string[];
characters?: Record<string, unknown>;
}
// === VALIDATION LOGIC ===
function validateCompleteness(synthesis: SynthesisDocument): CheckResult {
const notes: string[] = [];
let score = 0;
const maxScore = 10;
// Check meta fields
if (synthesis._meta?.synthesis_name) {
score += 1;
} else {
notes.push("Missing synthesis name");
}
if (synthesis._meta?.target_context) {
score += 1;
} else {
notes.push("Missing target context");
}
if (synthesis._meta?.primary_source) {
score += 1;
} else {
notes.push("Missing primary source reference");
}
if (synthesis._meta?.target_genre) {
score += 1;
} else {
notes.push("Missing target genre");
}
// Check context mapping
if (synthesis.context_mapping && Object.keys(synthesis.context_mapping).length > 0) {
score += 2;
if (Object.keys(synthesis.context_mapping).length >= 4) {
score += 1;
} else {
notes.push("Context mapping could be more detailed");
}
} else {
notes.push("Missing context mapping");
}
// Check function mappings
if (synthesis.function_to_form_mapping && Object.keys(synthesis.function_to_form_mapping).length > 0) {
score += 2;
const mappingCount = Object.keys(synthesis.function_to_form_mapping).length;
if (mappingCount >= 5) {
score += 1;
} else {
notes.push(`Only ${mappingCount} function mappings - consider adding more`);
}
} else {
notes.push("Missing function-to-form mappings");
}
// Check character synthesis
if (synthesis.character_synthesis && Object.keys(synthesis.character_synthesis).length > 0) {
// Score already at max if everything above passes
} else {
notes.push("Missing character synthesis");
}
return {
status: score >= 8 ? "pass" : score >= 5 ? "warn" : "fail",
score,
max_score: maxScore,
notes
};
}
function validateOrthogonality(synthesis: SynthesisDocument): CheckResult {
const notes: string[] = [];
let score = 0;
const maxScore = 10;
if (!synthesis.function_to_form_mapping) {
return {
status: "fail",
score: 0,
max_score: maxScore,
notes: ["No function mappings to check for orthogonality"]
};
}
const mappings = Object.entries(synthesis.function_to_form_mapping);
let passedChecks = 0;
let explicitlyMarked = 0;
for (const [func, mapping] of mappings) {
// Check if orthogonality was explicitly evaluated
if (mapping.orthogonality_check) {
explicitlyMarked++;
if (mapping.orthogonality_check.toLowerCase().includes("pass")) {
passedChecks++;
} else if (mapping.orthogonality_check.toLowerCase().includes("fail")) {
notes.push(`Orthogonality FAILED for: ${func}`);
} else {
notes.push(`Unclear orthogonality status for: ${func}`);
}
}
// Heuristic checks for surface translation
if (mapping.new_form && mapping.original_form) {
const original = mapping.original_form.toLowerCase();
const newForm = mapping.new_form.toLowerCase();
// Check for obvious 1:1 translations
const surfaceIndicators = ["space ", "cyber", "future ", "sci-fi ", "fantasy "];
for (const indicator of surfaceIndicators) {
if (newForm.includes(indicator) && !original.includes(indicator)) {
notes.push(`Possible surface translation: "${mapping.new_form}" - just adding setting prefix?`);
break;
}
}
}
}
// Score based on explicit checks
if (mappings.length > 0) {
if (explicitlyMarked === mappings.length) {
score += 4;
} else if (explicitlyMarked > 0) {
score += 2;
notes.push(`Only ${explicitlyMarked}/${mappings.length} mappings have explicit orthogonality check`);
} else {
notes.push("No explicit orthogonality checks recorded");
}
const passRate = passedChecks / mappings.length;
score += Math.round(passRate * 6);
}
return {
status: score >= 8 ? "pass" : score >= 5 ? "warn" : "fail",
score,
max_score: maxScore,
notes
};
}
function validateFunctionCoverage(synthesis: SynthesisDocument, source: DNADocument | null): CheckResult {
const notes: string[] = [];
let score = 0;
const maxScore = 10;
if (!synthesis.function_to_form_mapping) {
return {
status: "fail",
score: 0,
max_score: maxScore,
notes: ["No function mappings present"]
};
}
const mappedFunctions = Object.keys(synthesis.function_to_form_mapping);
// Basic: has some mappings
if (mappedFunctions.length > 0) {
score += 2;
}
// Check that mappings have functions_served
let functionsServed = 0;
for (const mapping of Object.values(synthesis.function_to_form_mapping)) {
if (mapping.functions_served && mapping.functions_served.length > 0) {
functionsServed += mapping.functions_served.length;
}
}
if (functionsServed >= 10) {
score += 3;
} else if (functionsServed >= 5) {
score += 2;
notes.push("Consider documenting more functions served by each mapping");
} else {
score += 1;
notes.push("Few functions documented - synthesis may have gaps");
}
// If we have source DNA, check coverage
if (source && source.structural_requirements) {
const requirements = source.structural_requirements;
let covered = 0;
for (const req of requirements) {
// Check if any mapping mentions this requirement
const reqWords = req.toLowerCase().split(/\s+/);
let found = false;
for (const mapping of Object.values(synthesis.function_to_form_mapping)) {
const mappingText = JSON.stringify(mapping).toLowerCase();
if (reqWords.some(word => word.length > 4 && mappingText.includes(word))) {
found = true;
break;
}
}
if (found) covered++;
}
const coverageRate = covered / requirements.length;
score += Math.round(coverageRate * 5);
if (coverageRate < 1) {
notes.push(`${requirements.length - covered}/${requirements.length} structural requirements may not be covered`);
}
} else {
// No source to check against - assume reasonable coverage
score += 3;
notes.push("No source DNA provided - cannot verify full function coverage");
}
return {
status: score >= 8 ? "pass" : score >= 5 ? "warn" : "fail",
score,
max_score: maxScore,
notes
};
}
function validateContextCoherence(synthesis: SynthesisDocument): CheckResult {
const notes: string[] = [];
let score = 0;
const maxScore = 10;
// Check context mapping exists and is substantive
if (!synthesis.context_mapping || Object.keys(synthesis.context_mapping).length === 0) {
return {
status: "fail",
score: 0,
max_score: maxScore,
notes: ["No context mapping present"]
};
}
const contextFields = Object.keys(synthesis.context_mapping);
const contextValues = Object.values(synthesis.context_mapping);
// Basic: has context mapping
score += 2;
// Check for key context elements
const desiredFields = ["setting", "power_structure", "information_control", "escape_prevention"];
let fieldsPresent = 0;
for (const field of desiredFields) {
if (contextFields.some(f => f.toLowerCase().includes(field.replace("_", "")))) {
fieldsPresent++;
}
}
score += Math.min(4, fieldsPresent);
if (fieldsPresent < desiredFields.length) {
notes.push(`Consider adding context for: ${desiredFields.filter(f =>
!contextFields.some(cf => cf.toLowerCase().includes(f.replace("_", "")))
).join(", ")}`);
}
// Check that context values are substantive (not just placeholders)
const substantiveValues = contextValues.filter(v => v && v.length > 10);
if (substantiveValues.length === contextValues.length) {
score += 2;
} else {
notes.push("Some context values seem like placeholders");
score += 1;
}
// Check function mappings fit context
if (synthesis.function_to_form_mapping) {
const contextText = JSON.stringify(synthesis.context_mapping).toLowerCase();
let coherent = 0;
const mappings = Object.values(synthesis.function_to_form_mapping);
for (const mapping of mappings) {
// Basic heuristic: new form should use words from context
if (mapping.new_form) {
const formWords = mapping.new_form.toLowerCase().split(/\s+/);
if (formWords.some(w => w.length > 4 && contextText.includes(w))) {
coherent++;
}
}
}
if (mappings.length > 0) {
const coherenceRate = coherent / mappings.length;
score += Math.round(coherenceRate * 2);
if (coherenceRate < 0.5) {
notes.push("Some new forms may not fit the defined context");
}
}
}
return {
status: score >= 8 ? "pass" : score >= 5 ? "warn" : "fail",
score,
max_score: maxScore,
notes
};
}
function validateGenreAlignment(synthesis: SynthesisDocument, targetGenre: string | null, source: DNADocument | null): CheckResult {
const notes: string[] = [];
let score = 0;
const maxScore = 10;
const genre = targetGenre || synthesis._meta?.target_genre;
if (!genre) {
return {
status: "warn",
score: 5,
max_score: maxScore,
notes: ["No target genre specified - cannot validate alignment"]
};
}
// Has explicit genre
score += 2;
// Check if source genre matches (if available)
if (source?.emotional_core?.primary_genre) {
if (source.emotional_core.primary_genre.toLowerCase() === genre.toLowerCase()) {
score += 3;
notes.push("Target genre matches source primary genre");
} else {
notes.push(`Source genre (${source.emotional_core.primary_genre}) differs from target (${genre}) - intentional shift?`);
score += 1; // Not inherently wrong, but flag it
}
} else {
score += 2; // No source to compare
}
// Check tone synthesis for genre appropriateness
if (synthesis.tone_synthesis) {
score += 2;
// Basic genre-tone heuristics
const tone = JSON.stringify(synthesis.tone_synthesis).toLowerCase();
const genreLower = genre.toLowerCase();
if (genreLower === "horror" && !tone.includes("dread") && !tone.includes("fear") && !tone.includes("unease")) {
notes.push("Horror genre but tone doesn't mention dread/fear/unease");
}
if (genreLower === "humor" && !tone.includes("comic") && !tone.includes("funny") && !tone.includes("wit")) {
notes.push("Humor genre but tone doesn't mention comedy elements");
}
if (genreLower === "drama" && tone.includes("light") && tone.includes("comedy")) {
notes.push("Drama genre but tone seems light - intentional dramedy?");
}
} else {
notes.push("No tone synthesis - harder to verify genre alignment");
}
// Check for explicit genre validation in document
if (synthesis.validation?.genre_check?.toLowerCase().includes("pass")) {
score += 3;
} else if (synthesis.validation?.genre_check) {
score += 1;
notes.push("Genre check in document doesn't indicate clear pass");
}
return {
status: score >= 8 ? "pass" : score >= 5 ? "warn" : "fail",
score,
max_score: maxScore,
notes
};
}
function runValidation(synthesis: SynthesisDocument, source: DNADocument | null, targetGenre: string | null): ValidationResult {
const completeness = validateCompleteness(synthesis);
const orthogonality = validateOrthogonality(synthesis);
const functionCoverage = validateFunctionCoverage(synthesis, source);
const contextCoherence = validateContextCoherence(synthesis);
const genreAlignment = validateGenreAlignment(synthesis, targetGenre, source);
const checks = {
function_coverage: functionCoverage,
orthogonality: orthogonality,
context_coherence: contextCoherence,
genre_alignment: genreAlignment,
completeness: completeness
};
// Aggregate issues and warnings
const issues: string[] = [];
const warnings: string[] = [];
for (const [name, check] of Object.entries(checks)) {
if (check.status === "fail") {
issues.push(`${name}: FAILED (${check.score}/${check.max_score})`);
issues.push(...check.notes.map(n => ` - ${n}`));
} else if (check.status === "warn") {
warnings.push(`${name}: WARNING (${check.score}/${check.max_score})`);
warnings.push(...check.notes.map(n => ` - ${n}`));
}
}
// Determine overall status
const failCount = Object.values(checks).filter(c => c.status === "fail").length;
const warnCount = Object.values(checks).filter(c => c.status === "warn").length;
let overallStatus: "pass" | "warn" | "fail";
if (failCount > 0) {
overallStatus = "fail";
} else if (warnCount > 1) {
overallStatus = "warn";
} else {
overallStatus = "pass";
}
// Determine readiness
const readyFor: string[] = [];
if (overallStatus === "pass") {
readyFor.push("outline-collaborator", "drafting");
} else if (overallStatus === "warn") {
readyFor.push("review and refinement");
} else {
readyFor.push("address issues before proceeding");
}
return {
synthesis_name: synthesis._meta?.synthesis_name || "Unknown",
overall_status: overallStatus,
checks,
issues,
warnings,
ready_for: readyFor
};
}
// === FORMATTING ===
function formatValidationResult(result: ValidationResult): string {
const lines: string[] = [];
const statusEmoji = result.overall_status === "pass" ? "[PASS]" :
result.overall_status === "warn" ? "[WARN]" : "[FAIL]";
lines.push(`# Validation Result: ${result.synthesis_name}`);
lines.push("");
lines.push(`## Overall Status: ${statusEmoji} ${result.overall_status.toUpperCase()}`);
lines.push("");
lines.push("## Check Results");
lines.push("");
lines.push("| Check | Status | Score |");
lines.push("|-------|--------|-------|");
for (const [name, check] of Object.entries(result.checks)) {
const emoji = check.status === "pass" ? "PASS" : check.status === "warn" ? "WARN" : "FAIL";
lines.push(`| ${name.replace(/_/g, " ")} | ${emoji} | ${check.score}/${check.max_score} |`);
}
lines.push("");
if (result.issues.length > 0) {
lines.push("## Issues (Must Fix)");
lines.push("");
for (const issue of result.issues) {
lines.push(issue);
}
lines.push("");
}
if (result.warnings.length > 0) {
lines.push("## Warnings (Consider)");
lines.push("");
for (const warning of result.warnings) {
lines.push(warning);
}
lines.push("");
}
lines.push("## Ready For");
lines.push("");
for (const ready of result.ready_for) {
lines.push(`- ${ready}`);
}
lines.push("");
// Detailed notes per check
lines.push("## Detailed Notes");
lines.push("");
for (const [name, check] of Object.entries(result.checks)) {
if (check.notes.length > 0) {
lines.push(`### ${name.replace(/_/g, " ")}`);
for (const note of check.notes) {
lines.push(`- ${note}`);
}
lines.push("");
}
}
return lines.join("\n");
}
// === MAIN ===
function main(): void {
const args = Deno.args;
// Help
if (args.includes("--help") || args.includes("-h")) {
console.log(`Validate Synthesis
Usage:
deno run --allow-read scripts/validate-synthesis.ts synthesis.json
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --against source.json
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --genre drama
deno run --allow-read scripts/validate-synthesis.ts synthesis.json --full
Options:
--against <file> Source DNA to validate coverage against
--genre <name> Target genre to check alignment
--full Run all checks with verbose output
--json Output as JSON
Checks Performed:
- Completeness: Are all required sections present?
- Orthogonality: Do new forms avoid surface translation?
- Function Coverage: Are source functions served?
- Context Coherence: Do forms fit the target context?
- Genre Alignment: Does synthesis deliver intended emotional experience?
`);
Deno.exit(0);
}
const isJson = args.includes("--json");
const isFull = args.includes("--full");
// Parse arguments
const againstIndex = args.indexOf("--against");
const againstFile = againstIndex !== -1 ? args[againstIndex + 1] : null;
const genreIndex = args.indexOf("--genre");
const genre = genreIndex !== -1 ? args[genreIndex + 1] : null;
// Find synthesis file (first positional argument)
const skipIndices = new Set<number>();
if (againstIndex !== -1) {
skipIndices.add(againstIndex);
skipIndices.add(againstIndex + 1);
}
if (genreIndex !== -1) {
skipIndices.add(genreIndex);
skipIndices.add(genreIndex + 1);
}
let synthesisFile: string | null = null;
for (let i = 0; i < args.length; i++) {
if (!args[i].startsWith("--") && !skipIndices.has(i)) {
synthesisFile = args[i];
break;
}
}
if (!synthesisFile) {
console.error("Error: Please provide a synthesis file to validate");
console.error("Usage: deno run --allow-read scripts/validate-synthesis.ts synthesis.json");
Deno.exit(1);
}
// Load synthesis document
let synthesis: SynthesisDocument;
try {
const content = Deno.readTextFileSync(synthesisFile);
synthesis = JSON.parse(content);
} catch (e) {
console.error(`Error reading synthesis file: ${e}`);
Deno.exit(1);
}
// Load source DNA if provided
let source: DNADocument | null = null;
if (againstFile) {
try {
const content = Deno.readTextFileSync(againstFile);
source = JSON.parse(content);
} catch (e) {
console.error(`Error reading source DNA file: ${e}`);
Deno.exit(1);
}
}
// Run validation
const result = runValidation(synthesis, source, genre);
// Output
if (isJson) {
console.log(JSON.stringify(result, null, 2));
} else {
console.log(formatValidationResult(result));
}
}
main();
Related skills
How it compares
Use adaptation-synthesis for structured learning-loop consolidation; use implementation skills once requirements are stable enough to build.
FAQ
What does adaptation-synthesis produce?
adaptation-synthesis produces consolidated adaptation plans from feedback, experiments, and changing requirements, guiding next iterations of agent behavior or early prototypes before full build commitment.
When should adaptation-synthesis be used?
adaptation-synthesis should be used during validate-phase iteration when agent behavior or prototypes must evolve from user feedback and experiment data instead of jumping straight to production implementation.