write-contract
Write production-quality GenLayer intelligent contracts. Always pins concrete GenVM runner version hashes and never uses local-only test/latest runner aliases. Covers equivalence principles, storage rules, LLM resilience, and cross-contract interaction.
Install / Use
npx skills add internet-court/internet-court-skill --skill write-contractInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
AI & Machine LearningSupported Platforms
Tags
Our assessment of write-contract
write-contract scores 96/100 on our quality scale, 75th of 814 AI & Machine Learning skills we index (top 10%).
Its SKILL.md is 24 KB long, well organised into 50 sections with 25 code examples: a thorough specification that gives an agent plenty to work with.
With 6,129 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated 39 days ago, so write-contract is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 88/100, with 1 caution from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
write-contract compared with similar skills
All 4 of these similar skills score higher than write-contract; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| write-contract (this skill)by internet-court | 96 | 6.1k | 39d ago | SKILL.md |
| claude-memby thedotmack | 100 | 94.8k | today | CLAUDE.md |
| Understand-Anythingby Egonex-AI | 100 | 84.4k | today | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.0k | 1d ago | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.1k | today | CLAUDE.md |
Frequently asked questions
- How do I install write-contract?
- Run
npx skills add internet-court/internet-court-skill --skill write-contract. The install tabs above show the steps for each supported agent. - Which AI agents does write-contract work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is write-contract safe to use?
- It declares no license and scores 88/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is write-contract still maintained?
- The repository was last updated 39 days ago, so write-contract is actively maintained.
Skill content
View source on GitHubname: write-contract description: Write production-quality GenLayer intelligent contracts. Always pins concrete GenVM runner version hashes and never uses local-only test/latest runner aliases. Covers equivalence principles, storage rules, LLM resilience, and cross-contract interaction. allowed-tools:
- Bash
- Read
- Write
- Edit
- Grep
- Glob
Write Intelligent Contract
Guidance for writing GenLayer intelligent contracts that pass consensus, handle errors correctly, and survive production.
Critical: Pin the Runner Version
All GenLayer networks reject py-genlayer:test, py-genlayer:latest, and
unversioned runner aliases. Every generated contract MUST start with a pinned
runner dependency header.
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
test and latest are local-development aliases for GenLayer runtime
developers. They may work only in a specially configured local Studio
environment with a GenLayer developer environment variable, but they do not work
on GenLayer networks and must not appear in generated user contracts.
Before returning any contract code, verify:
- The first line is a pinned
Dependsrunner version hash. - There is no
py-genlayer:test. - There is no
py-genlayer:latest. - There is no unversioned
py-genlayer.
Always lint with genvm-lint check after writing or modifying a contract.
When to Use GenLayer
Before writing code, decide whether the feature actually needs GenLayer consensus. Recent builder feedback shows many projects start by treating GenLayer as a generic AI backend; push them toward a clear on-chain consensus role.
Use GenLayer when the contract must coordinate or settle around a subjective, external, or AI-mediated judgment that multiple validators should verify independently:
- Dispute resolution where evidence must be evaluated and the result affects escrow, payouts, reputation, or access.
- Prediction/oracle-style markets where the contract needs an independently validated outcome from external evidence.
- Compliance, moderation, or scoring workflows where the final decision must be reproducible enough for validator agreement but cannot be reduced to a simple deterministic API call.
- Autonomous agents that need transparent settlement, appeals, and auditable state transitions rather than a private off-chain decision.
Prefer a normal backend, frontend, or off-chain LLM workflow when:
- The frontend already computes the final answer and GenLayer would only rubber-stamp it.
- The contract only stores user-provided data with no validator-verifiable judgment.
- A deterministic smart contract, REST API, or database job can perform the work without AI consensus.
- The data-fetching/prompting step is not tied to an on-chain state transition, escrow, payout, or appealable decision.
For every contract, write down the boundary before implementation:
- Frontend/backend owns: UI, user auth, indexing, non-authoritative previews, cached market data, and convenience analytics.
- GenLayer contract owns: the minimum state transition that needs consensus, the evidence inputs, the validator comparison rule, the final settlement effect, and any appeal/rotation path.
- External sources own: raw facts or documents; do not treat them as trusted unless validators can re-fetch, normalize, and compare them.
If the boundary is unclear, create a one-page architecture note before coding: user action -> evidence source -> nondeterministic call -> equivalence principle -> state update -> user-visible settlement.
Contract Skeleton
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
from genlayer import *
class MyContract(gl.Contract):
# Storage fields — typed, persisted on-chain
owner: Address
items: TreeMap[str, Item]
item_order: DynArray[str]
def __init__(self, param: str):
self.owner = gl.message.sender_account
@gl.public.view
def get_item(self, item_id: str) -> dict:
return {"id": item_id, "value": self.items[item_id].value}
@gl.public.write
def set_item(self, item_id: str, value: str) -> None:
if gl.message.sender_account != self.owner:
raise gl.UserError("Only owner")
self.items[item_id] = Item(value=value)
self.item_order.append(item_id)
Runner Dependencies
The first line of a contract declares the GenVM Python runner. Always pin a
specific runner version hash. All GenLayer networks reject test, latest, and
unversioned runner aliases in generated contracts.
Single-file Python contracts
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
Multi-file Python contract packages
Use py-genlayer-multi when the contract is packaged across multiple files.
# { "Depends": "py-genlayer-multi:06zyvrlivjga0d5jlpdbprksc0pa6jmllxvp8s20hq1l512vh5yk" }
Contracts using embeddings or semantic search
Add py-lib-genlayer-embeddings before the main Python runner with a Seq
block.
# {
# "Seq": [
# { "Depends": "py-lib-genlayer-embeddings:0bmbm3cyfwxsyh454z53vxqjf47wz2q7smcqp1q4g4a6k2kidnyk" },
# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" }
# ]
# }
Equivalence Principle — Which One to Use
This is the most critical decision. Pick wrong and consensus will fail or be trivially exploitable.
Decision Tree
Can validators reproduce the exact same normalized output?
├── YES → strict_eq
│ Exact match. Use when outputs are deterministic or can be
│ canonicalized (e.g., JSON with sort_keys=True).
│ Examples: blockchain RPC, stable REST APIs.
│
└── NO → Write a custom validator function (run_nondet_unsafe)
Default: produce independent evidence. Usually rerun the same task
and compare decision fields, derived status, scores, or other stable
outputs with explicit tolerances. Only skip the second answer when the
validator can judge the leader output against source data and criteria.
GenLayer also provides prompt_comparative and prompt_non_comparative as convenience wrappers, but most contracts outgrow them quickly. Start with a custom validator function for full flexibility.
Independent verification by default
For LLM and web operations, never trust the leader. The validator must verify the substance of the leader's answer using evidence other than the leader's answer alone. In practice that means one of:
- Rerun the same LLM/web task and compare the stable decision fields.
- Fetch the same source data and independently derive the status being stored.
- Run an explicit comparative LLM judgment over the leader output and validator output.
- For open-ended outputs, judge the leader output against the same input/source data and explicit criteria.
Do not write validators that only check leader_result.calldata for a valid JSON shape, allowed enum value, non-empty summary, or confidence in range. That is leader-output-only validation, not consensus. It trusts the leader's substantive answer 100% and only proves that the leader formatted the answer correctly.
Non-comparative validation does not mean "trust the leader." It means the validator does not produce a second candidate answer. It still must read the same input/source data and ask whether the leader output is valid under clear criteria. A summary validator, for example, should check whether the proposed summary is faithful to the article, covers the material points, avoids hallucinated facts, and satisfies length/style constraints.
Classification, scoring, extraction, authenticity decisions, safety decisions, ranking, and settlement logic almost always need comparative validation: rerun or independently derive the answer, then compare the decision field, extracted fields, score bucket, or derived status. If the validator only checks that the leader chose an allowed label such as authentic, suspicious, or inconclusive, the leader is deciding alone.
strict_eq — Deterministic calls only
def fetch_balance(self) -> int:
def call_rpc():
res = gl.nondet.web.post(rpc_url, body=payload, headers=headers)
return json.loads(res.body.decode("utf-8"))["result"]
return gl.eq_principle.strict_eq(call_rpc)
Never use for LLM calls or web pages that change between requests.
Custom Validator Function (most common)
The default choice for non-deterministic operations. You write the leader function and a validator function with your own comparison logic. The validator should independently perform or verify the same substantive task, then compare the result fields that matter.
def score_content(self, content: str) -> dict:
def leader_fn():
analysis = gl.nondet.exec_prompt(prompt, response_format="json")
score = _parse_llm_score(analysis)
return {"score": score, "analysis": str(analysis.get("analysis", ""))}
def validator_fn(leaders_res: gl.vm.Result) -> bool:
if not isinstance(leaders_res, gl.vm.Return):
return _handle_leader_error(leaders_res, leader_fn)
validator_result = leader_fn()
leader_score = leaders_res.calldata["score"]
validator_score = validator_result["score"]
# Gate check: if either is zero (reject), both must agree
if (leader_score == 0) != (validator_score == 0):
return False
# Tolerance: within 5x/0.5x bounds
if leader_score > 0 and validator_score > 0:
ratio = leader_score / validator_score
if ratio > 5.0 or ratio < 0.2:
return False
return True
return gl.vm.run_nondet_unsafe(leader_fn, validator_fn)
Convenience Wrappers
prompt_comparative reruns the task and sends both outputs to an LLM with your principle string. prompt_non_comparative does not rerun the task; it asks validators to judge the leader output against input data and criteria. Both are convenient for prototyping but limited - for most production contracts, prefer a custom validator function with explicit comparison logic.
Prefer prompt_comparative unless you can explain why independently doing the task again would be meaningless and how the validator will still verify the leader output against source data. If the only reason is "outputs may differ," compare the decision fields, normalize the output, derive a status, or use tolerance instead of dropping comparison entirely.
def resolve(self) -> str:
def analyze():
page = gl.get_webpage(url, mode="text")
return gl.exec_prompt(f"Analyze: {page}\nReturn JSON with outcome and reasoning.")
return gl.eq_principle.prompt_comparative(
analyze,
principle="`outcome` field must be exactly the same. All other fields must be similar.",
)
Error Classification
Classify errors so validators know how to compare them. This is critical for consensus on failure paths.
ERROR_EXPECTED = "[EXPECTED]" # Business logic (deterministic) — exact match required
ERROR_EXTERNAL = "[EXTERNAL]" # External API 4xx (deterministic) — exact match required
ERROR_TRANSIENT = "[TRANSIENT]" # Network/5xx (non-deterministic) — agree if both transient
ERROR_LLM = "[LLM_ERROR]" # LLM misbehavior — always disagree, force rotation
Canonical error handler for validators
def _handle_leader_error(leaders_res, leader_fn) -> bool:
leader_msg = leaders_res.message if hasattr(leaders_res, 'message') else ''
try:
leader_fn()
return False # Leader errored, validator succeeded — disagree
except gl.vm.UserError as e:
validator_msg = e.message if hasattr(e, 'message') else str(e)
# Deterministic errors: must match exactly
if validator_msg.startswith(ERROR_EXPECTED) or
Truncated for display — read the full file on GitHub.
Related Skills
claude-mem
94.8kPersistent Context Across Sessions for Every Agent – Captures everything your agent does during sessions, compresses it with AI, and injects relevant context back into future sessions. Works with Claude Code, OpenClaw, Codex, Gemini, Hermes, Copilot, OpenCode + More
Understand-Anything
84.4kGraphs that teach > graphs that impress. Turn any code into an interactive knowledge graph you can explore, search, and ask questions about. Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI, and more.
headroom
74.0kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.1kOpen-source super AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
