Your AI coding assistant doesn't know Compact. It knows TypeScript, Solidity, Rust, but Midnight's ZK smart contract language didn't exist when most models were trained. Ask it to write a Compact contract and you'll get plausible-looking code that won't compile.
midnight_agent_skills is a set of 4 agent skills that fix this. Install them once, and your AI assistant has accurate knowledge of Compact syntax, the Midnight SDK, network config, and the gotchas that trip up real builders.
This is a walkthrough of using those skills to build your first Midnight dApp.
What are agent skills?
Agent skills are structured knowledge files that AI coding assistants load at context time. Instead of relying on training data, the assistant reads the skill files directly, so it gets accurate, current information rather than hallucinated guesses.
The midnight_agent_skills package has 4 skills:
- midnight-concepts: ZK architecture, DUST/NIGHT tokenomics, Kachina protocol
- midnight-compact: Compact language, circuits, ledger operations, best practices
- midnight-api: SDK integration, wallet connection, contract deployment
- midnight-network: Node setup, Docker, indexer, proof server
Step 1: Install the skills
npx skills add https://github.com/mzf11125/midnight_agent_skills
Or pick individual skills:
npx skills add https://github.com/mzf11125/midnight_agent_skills --skill midnight-compact
npx skills add https://github.com/mzf11125/midnight_agent_skills --skill midnight-api
Step 2: Start the proof server
Midnight generates ZK proofs client-side, your data stays on your machine. You need a local proof server running before you can deploy anything.
docker run -p 6300:6300 midnightnetwork/proof-server -- \
'midnight-proof-server --network preprod'
Check it's up:
curl http://localhost:6300
# We're alive 🎉!
Step 3: Scaffold your project
npx create-midnight-app my-first-dapp
cd my-first-dapp
Step 4: Write your contract
Open your AI assistant and ask it to write a Midnight contract. With the skills loaded, it knows the correct syntax.
Here's a simple owner-gated counter, only the deployer can increment it:
pragma language_version >= 0.20;
import CompactStandardLibrary;
export ledger counter: Counter;
export ledger owner: Bytes<32>;
witness local_secret_key(): Bytes<32>;
export circuit initialize(): [] {
const pk = publicKey(local_secret_key()).bytes;
owner.write(disclose(pk));
}
export circuit increment(): [] {
const caller = publicKey(local_secret_key()).bytes;
assert(disclose(caller) == owner.read(), "Not authorized");
counter.increment(1);
}
Things the skills teach your AI that it wouldn't otherwise know:
-
export circuitnotfunction, circuits declare constraints, they don't execute -
disclose()is required when moving witness data to the public ledger, the compiler rejects code without it -
Counteruses.increment()and.read(), not.value() - No recursion, no unbounded loops, circuits must compile to a fixed-size constraint system
Step 5: Compile
compact build src/counter.compact src/managed/counter
Success looks like:
Fetching public parameters for k=10 [====================] 192.38 KiB
circuit "increment" (k=10, rows=29)
Overall progress [====================] 1/1
Step 6: Deploy
With the midnight-api skill loaded, your AI generates the correct facade 4.x pattern:
import { WalletFacade } from '@midnight-ntwrk/wallet-sdk-facade';
import { CounterContract } from './managed/counter/contract/index.js';
// facade 4.x, the old WalletFacade.init() hangs silently on standalone nodes
const wallet = new WalletFacade(shielded, unshielded, dust);
await wallet.start();
const contract = new CounterContract();
const deployed = await contract.deploy(providers, { privateCounter: 0 });
console.log('Deployed at:', deployed.deployTxData.public.contractAddress);
The skills include the SDK compatibility matrix. Your AI knows that wallet-sdk-facade@2.x uses WalletFacade.init() which hangs silently on standalone nodes, and that 4.x switched to new WalletFacade(...) + .start().
Step 7: Run a pre-flight check
Before you spend hours debugging, run:
npx midnight-doctor
It reads your package.json, running Docker containers, and config files, then cross-references them against a known compatibility matrix. The midnight-api skill documents the most common silent failures:
| Symptom | Root cause |
|---|---|
waitForSyncedState() hangs forever |
facade 2.x + standalone node mismatch |
| Transactions silently fail | Duplicate @midnight-ntwrk/ledger-v7 in node_modules |
| Indexer crash-loops | Missing subscription: block in indexer.yml
|
What the skills know that your AI doesn't
The skills pull from the official Midnight docs plus 19 community articles from the Midnight Aliit Fellowship, builders documenting real production failures.
Mental model shifts:
- Circuits declare constraints, they don't execute.
assertis a constraint declaration, not a runtime guard, if the condition is false, the proof can't be generated. -
disclose()is a compile-time annotation, not encryption. The compiler tracks witness data through arithmetic and rejects undeclared disclosures. - Block limits are hard limits, not gas costs.
BlockLimitExceededmeans your transaction can't execute at all.
On-chain design patterns:
- Flat maps over struct maps, reading a struct pulls every field into the circuit
- Off-chain computation + Merkle root, the chain verifies, it doesn't compute
- Minimal on-chain state, only what the chain needs to enforce
Common syntax gotchas:
-
counter.read()notcounter.value() - Enum access uses
.not::,GameState.playingnotGameState::playing - Witness functions have no body, declaration only
-
returninsideforloops is not allowed, usefold
Install and start building
npx skills add https://github.com/mzf11125/midnight_agent_skills
The skills are open source. If you hit a pattern that's missing, PRs are open.
Top comments (0)