Skip to content

Contributing Circuits

This guide walks you through creating, validating, and publishing a quantum circuit on QubitHub. By the end, your circuit will be browsable, forkable, and executable by anyone on the platform.

Looking for how to change someone else’s circuit? See Contributing to a circuit you don’t own.


Short answer: fork it. Forking is how contribution works on QubitHub, and a fork is a finished contribution — not a workaround for a missing step.

QubitHub has no pull requests. There is no way to propose a change back into someone else’s circuit, and no merge queue. This is a deliberate choice, not a gap waiting to be filled — see why below.

ActionOn your own circuitsOn someone else’s public circuit
git clone✅✅ (no account needed)
Run it✅✅
git push✅❌ 403 Write access required
Fork it✅✅
Push to your fork✅✅ — it’s yours
Propose a change back—❌ not supported

Org-owned circuits follow the same rule with org membership: active OWNER and ADMIN members can push; everyone else forks.

Terminal window
# 1. Fork on the circuit page, or from the CLI
qubithub circuits fork alice-q/vqe-ansatz
# 2. Clone your fork and work in it
git clone https://qubithub.co/your-name/vqe-ansatz.git
cd vqe-ansatz
# 3. Push to your fork — an API key goes in the password field
git push

Your fork keeps the full git history of the original and carries a “forked from” link back to it, shown on your circuit’s page. That link is the provenance record: readers can see what your work is built on, and the original’s fork count reflects that someone built on it.

Credit the original in your README.md and link its URL. If the original carries a LICENSE file, follow it — absent a LICENSE, content is publicly visible but not licensed for redistribution (the same default GitHub applies).

Check the license before you fork, not after. It’s shown next to the Fork button on every circuit page. Circuits created before licensing shipped may show No license; that means nobody chose, and it carries the all-rights-reserved default — ask the owner rather than assuming. Your fork inherits the original’s license, since the LICENSE file is copied with the code. See Licensing.

  • In a QubitHub/* circuit (the curated collection) — use the feedback widget on the site. It reaches the maintainers.
  • In someone else’s circuit — QubitHub does not currently carry a message to a circuit’s owner. There’s no in-app inbox and profiles don’t expose contact details. Your options are to fork and fix it in your copy, or reach the author through whatever contact they put in their own README.

A circuit is usually a published result, not a shared codebase. When someone improves an ansatz or changes a parameter, they have produced a new result that deserves its own attribution, not a patch to yours — and merging it would quietly change the artifact a paper or blog post points at. Forking with visible lineage gives the derived work its own identity and keeps the original citable and stable.

If that stops being the right trade-off, we’ll say so and build the alternative. Until then, this is the model and it’s the whole model.


Every circuit on QubitHub is a small repository with three files:

my-circuit/
├── circuit.py # Your quantum circuit code
├── qubithub.toml # Manifest describing the circuit
└── README.md # Documentation shown on the circuit page

Optional files like params.json or circuit.qasm can be included too.


If you’re already familiar with quantum circuits and just want to publish:

Terminal window
# 1. Scaffold
qubithub circuits init my-circuit --framework qiskit
# 2. Edit circuit.py, qubithub.toml, README.md
# 3. Push (creates the circuit if it doesn't exist)
cd my-circuit/
qubithub circuits push --create

Read on for the full walkthrough.


The CLI generates a starter project with all three required files:

Terminal window
qubithub circuits init my-circuit --framework qiskit

Options:

FlagDefaultDescription
--frameworkqiskitqiskit, pennylane, cirq, or openqasm3
--qubits2Number of qubits
--titleDerived from nameHuman-readable title

This creates a my-circuit/ directory with templates for circuit.py, qubithub.toml, and README.md.


Your circuit.py should define a function that creates and returns a quantum circuit. The convention is create_circuit() for Qiskit and Cirq, and circuit() for PennyLane (matching each framework’s idiom).

"""
My Circuit
==========
Brief description of what this circuit does.
Category: algorithm
Difficulty: beginner
Framework: Qiskit
Qubits: 2
"""
from qiskit import QuantumCircuit
def create_circuit() -> QuantumCircuit:
"""Create and return the quantum circuit."""
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
return qc
import pennylane as qml
from pennylane import numpy as np
dev = qml.device("default.qubit", wires=2)
@qml.qnode(dev)
def circuit():
"""Build and return the quantum circuit."""
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.counts(wires=range(2))
import cirq
def create_circuit() -> cirq.Circuit:
"""Create and return the quantum circuit."""
q0, q1 = cirq.LineQubit.range(2)
return cirq.Circuit([
cirq.H(q0),
cirq.CNOT(q0, q1),
cirq.measure(q0, q1, key="result"),
])

The qubithub.toml manifest is the single source of truth for your circuit’s metadata. It uses a progressive complexity model — start minimal, add detail as needed.

schema_version = "1.0.0"
[project]
name = "my-circuit"
title = "My Circuit"
type = "circuit"
framework = "qiskit"
entry_point = "circuit.py"
qubits = 2

These 6 fields are all you need to push.

Add execution defaults, difficulty, and tags for discoverability:

schema_version = "1.0.0"
[project]
name = "my-circuit"
title = "My Circuit"
type = "circuit"
framework = "qiskit"
entry_point = "circuit.py"
qubits = 2
depth = 4
gates = ["H", "CX", "RY"]
category = "algorithm"
difficulty = "intermediate"
tags = ["variational", "optimization"]
description = "A brief description of what this circuit does and why."
[execution]
default_backend = "aer_simulator"
default_shots = 1024
timeout_seconds = 30

Add educational content, expected output, hardware notes, and references:

schema_version = "1.0.0"
[project]
name = "bell-state"
title = "Bell State"
type = "circuit"
framework = "qiskit"
framework_version = "1.3.0"
entry_point = "circuit.py"
qubits = 2
depth = 2
gates = ["H", "CX"]
category = "entanglement"
difficulty = "beginner"
tags = ["entanglement", "epr", "foundational", "bell-pair"]
description = """
Creates the Bell state |Phi+> = (|00> + |11>)/sqrt(2), the simplest \
demonstration of quantum entanglement.\
"""
[execution]
default_backend = "aer_simulator"
default_shots = 1024
timeout_seconds = 10
[hardware]
connectivity = "any"
min_qubits = 2
required_gates = ["h", "cx"]
[educational]
level = "beginner"
concepts = ["entanglement", "superposition", "measurement"]
prerequisites = []
learning_outcomes = [
"Create a maximally entangled two-qubit state",
"Understand correlated measurement outcomes",
]
estimated_time = "10 minutes"
next_circuits = ["ghz-state", "quantum-teleportation"]
[expected_output]
dominant_states = ["00", "11"]
probability_range = [0.45, 0.55]
# Note: forbidden_states is not part of the validated spec but is
# conventionally included as documentation for readers
[[references.papers]]
title = "On the Einstein Podolsky Rosen Paradox"
authors = ["Bell, J.S."]
year = 1964
doi = "10.1103/PhysicsPhysiqueFizika.1.195"
[[references.textbooks]]
title = "Quantum Computation and Quantum Information"
authors = ["Nielsen, M.A.", "Chuang, I.L."]
section = "Section 1.3.6"

For the complete field reference, see qubithub.toml Reference.


A good README is the difference between a circuit people use and one they skip. Structure yours in four layers:

Start with a plain-English explanation. Use analogies. No math yet.

“The Bell state is like flipping two magic coins that always land the same way — both heads or both tails, never one of each.”

Explain what the circuit does step by step. Include a circuit diagram:

┌───┐
q_0: ┤ H ├──■──
└───┘┌─┴─┐
q_1: ─────┤ X ├
└───┘

Show the state evolution for readers who want the math:

|00⟩ → H⊗I → (|0⟩+|1⟩)/√2 ⊗ |0⟩ → CNOT → (|00⟩+|11⟩)/√2

Explain code-level choices: why these gates, why this ordering, what the parameters mean.

# My Circuit
Brief description (1-2 sentences).
| Property | Value |
|----------|-------|
| Level | Beginner / Intermediate / Advanced |
| Framework | Qiskit |
| Qubits | 2 |
| Depth | 4 |
| Time | ~10 minutes |
## What You'll Learn
- Learning outcome 1
- Learning outcome 2
## Background
Plain-English explanation of the algorithm or concept.
## Circuit
Step-by-step walkthrough with circuit diagram.
## Expected Output
| State | Probability |
|-------|------------|
| `00` | ~50% |
| `11` | ~50% |
## Try It Yourself
1. Variation to try (e.g., "Change the initial state to |01⟩")
2. Extension (e.g., "Add a third qubit to make a GHZ state")
## References
- Author (Year). "Title." Journal. DOI.

Before pushing, check your manifest parses correctly:

Terminal window
# View parsed metadata from qubithub.toml
qubithub circuits metadata my-circuit/

To test your circuit on QubitHub after pushing, use execute with the remote repo name:

Terminal window
qubithub execute alice-q/my-circuit --shots 1024 --watch

The CLI validates your qubithub.toml automatically during push and will report any errors.


Terminal window
cd my-circuit/
qubithub circuits push --create -m "Initial circuit"

Flags:

FlagDescription
--createCreate the circuit on QubitHub if it doesn’t exist yet
--nameOverride the circuit name (default: from qubithub.toml)
-mCommit message for this version

The CLI validates your files, then uploads them. You’ll see each file’s upload status:

Validating my-circuit/... ✓
Uploading circuit.py... ✓ (v1)
Uploading qubithub.toml... ✓ (v1)
Skipping README.md (not a pushable extension)
Circuit published: https://qubithub.co/alice-q/my-circuit

Push again without --create:

Terminal window
qubithub circuits push -m "Add parameterized rotation"

Each push creates a new version. Version history is visible on the circuit’s page.


The CLI checks these rules before uploading:

RuleRequirement
Required filescircuit.py, README.md, and either qubithub.toml or metadata.json must be present locally (README.md is validated but not uploaded)
TOML syntaxMust be valid TOML
Required fieldsname, title, type, framework, entry_point, qubits
Name formatLowercase, hyphens only, 1-100 characters
Frameworkqiskit, pennylane, cirq, or openqasm3
Difficultybeginner, intermediate, or advanced (if specified)
GatesUse gate names from your circuit’s framework (Qiskit: CX, PennyLane/Cirq: CNOT)
Shots1-100,000 (if default_shots specified)
Timeout1-300 seconds (if timeout_seconds specified)
File extensions.py, .json, .qasm, .qpy, .toml (others are skipped)
File size10 MB per file maximum
ErrorFix
Missing required field: qubitsAdd qubits = N to [project]
Invalid framework: QiskitUse lowercase: framework = "qiskit"
Invalid difficulty: BeginnerUse lowercase: difficulty = "beginner"
probability_range must have exactly 2 elementsUse [0.45, 0.55] not [0.45, 0.50, 0.55]

Use this checklist before publishing to ensure your circuit meets quality standards.

  • Circuit executes without errors on the specified backend
  • qubithub.toml has all 6 required fields
  • README.md exists and is meaningful (not just the template)
  • Code defines the circuit function (create_circuit() for Qiskit/Cirq, circuit() for PennyLane)
  • README uses the 4-layer structure (intuition → functional → mathematical → implementation)
  • README is substantial (30+ lines with meaningful content)
  • qubithub.toml includes depth, gates, difficulty, and tags
  • [educational] section filled out (concepts, prerequisites, learning outcomes)
  • [expected_output] specifies dominant_states and probability_range
  • Code has a module-level docstring with metadata
  • Code follows framework best practices (type hints, docstrings)
  • Full [references] section with papers and/or textbooks
  • “Try It Yourself” exercises in the README
  • [hardware] section with connectivity and gate requirements
  • Multiple [implementations] across frameworks
  • [reproducibility] section with seed and transpilation settings

Choose the right difficulty level for your circuit:

LevelQubitsDepthGatesParameterized?Examples
Beginner1-3≤10Basic (H, X, Y, Z, CX, CZ)NoBell State, Deutsch-Jozsa, Superdense Coding
Intermediate2-10≤50+ Rotation (RX, RY, RZ)OftenVQE, QAOA, Grover’s Search, QFT
Advanced4+AnyComplex sequencesUsuallyQuantum Kernels, Research reproductions, Custom ansatze

Tag your circuit with the most specific category:

CategoryDescription
entanglementBell states, GHZ, W states
algorithmGrover’s, Shor’s, Deutsch-Jozsa
chemistryVQE, molecular simulation
optimizationQAOA, MaxCut, TSP
machine_learningQuantum kernels, QNNs, classifiers
error_correctionBit-flip, Shor code, surface code
communicationTeleportation, superdense coding, QKD
transformQFT, QPE
cryptographyQKD protocols, post-quantum primitives
simulationHamiltonian simulation, Trotterization
utilityState preparation, oracle construction
ansatzHardware-efficient, UCCSD, problem-specific
researchPaper reproductions, novel circuits

Here’s the Bell State circuit as a complete example of all three files working together.

circuit.py:

"""
Bell State Circuit
==================
Creates the maximally entangled Bell state |Phi+> = (|00> + |11>)/sqrt(2).
Category: Entanglement
Difficulty: Beginner
Framework: Qiskit
Qubits: 2
Depth: 2
Gates: H, CX
"""
from qiskit import QuantumCircuit
def create_circuit() -> QuantumCircuit:
"""Create the Bell state |Phi+>."""
qc = QuantumCircuit(2)
qc.h(0) # Put qubit 0 in superposition
qc.cx(0, 1) # Entangle qubit 0 and qubit 1
return qc

qubithub.toml:

schema_version = "1.0.0"
[project]
name = "bell-state"
title = "Bell State"
type = "circuit"
framework = "qiskit"
entry_point = "circuit.py"
qubits = 2
depth = 2
gates = ["H", "CX"]
category = "entanglement"
difficulty = "beginner"
tags = ["entanglement", "epr", "foundational"]
description = "Creates the Bell state |Phi+>, the simplest demonstration of quantum entanglement."
[execution]
default_backend = "aer_simulator"
default_shots = 1024
[expected_output]
dominant_states = ["00", "11"]
probability_range = [0.45, 0.55]
# Note: forbidden_states is not part of the validated spec but is
# conventionally included as documentation for readers

README.md (abbreviated):

# Bell State
Creates the maximally entangled Bell state |Phi+⟩ = (|00⟩ + |11⟩)/√2.
| Property | Value |
|----------|-------|
| Level | Beginner |
| Framework | Qiskit |
| Qubits | 2 |
| Time | ~10 minutes |
## What You'll Learn
- Create a maximally entangled two-qubit state using H and CNOT gates
- Understand why entangled qubits always produce correlated measurements
## Background
The Bell state is like flipping two magic coins — they always land the
same way. Both heads or both tails, never one of each.
## Circuit
┌───┐
q_0: ┤ H ├──■──
└───┘┌─┴─┐
q_1: ─────┤ X ├
└───┘
1. **H gate** on qubit 0: creates superposition (|0⟩+|1⟩)/√2
2. **CX gate**: entangles qubit 0 and qubit 1
## Expected Output
| State | Probability |
|-------|------------|
| `00` | ~50% |
| `11` | ~50% |
| `01` | ~0% (forbidden) |
| `10` | ~0% (forbidden) |
## Try It Yourself
1. Change `qc.h(0)` to `qc.x(0); qc.h(0)` — which Bell state do you get?
2. Add a third qubit to create a GHZ state
3. Add `qc.measure_all()` and run with 4096 shots

CommandDescription
qubithub circuits init NAME [DIR]Scaffold a new circuit (--framework, --qubits, --title)
qubithub circuits push [DIR]Validate and upload (--create, --name, -m MESSAGE)
qubithub circuits clone REPO [DIR]Download a circuit locally
qubithub circuits fork REPOFork to your account (--name CUSTOM_NAME)
qubithub circuits listBrowse public circuits (--framework, --tag, --sort, --limit)
qubithub circuits info REPOView circuit details
qubithub circuits metadata [DIR]Show parsed manifest (--format json|toml)
qubithub execute REPORun a circuit remotely (--framework, --backend, --backend-type, --shots, --watch)

For full CLI documentation, see CLI Quickstart.