> add retry logic with backoff to my API client
searching the registry…
$ cartograph search "retry with backoff"
universal-retry-backoff-python v2.1.0 · 4.8
$ cartograph install universal-retry-backoff-python
✓ installed → cg/
wiring it into api/client.py
+ @retry(max=5, base=0.2) on client.post()
$ python app.py
✓ POST /sync retried on 503, then 200

Agent-native · reuse your solutions

Amplify your code
with reusable modules

Built for the way you code now.

Cartograph is built for agents. MCP support and a native command for appending to your instruction file. Make your agent reach for a proven widget instead of rewriting logic from scratch.

  • search and inspect the registry
  • install and status for installed widgets
  • create, validate, and checkin new widgets
  • registry, rules, and config for your setup
Full setup · MCP
$ claude mcp add --scope user cartograph -- cartograph-mcp
Just the CLI
$ cartograph setup --agent claude
rtl-counter-systemverilog
$ cartograph create counter --domain rtl --language systemverilog§ 03 · Anatomy

A widget, up close.

One command scaffolds a full widget. Shown is the starter for a SystemVerilog widget.

rtl-counter-systemverilog/
// counter.sv — Counter
//
// Every synthesizable parameter must have a default and a unit comment.
// No `initial` blocks, `#delays`, `timescale`, or $display in src/.
// Use always_comb / always_ff only — `always @(...)` is blocked.
// Vendor primitives allowed only if declared in dependencies.

module counter #(
    // -- Parameters (variation points) ----------------------------------------
    parameter int DATA_WIDTH = 8   // bits — width of the data bus
)(
    input  logic                  clk,    // system clock
    input  logic                  rst_n,  // active-low synchronous reset
    input  logic [DATA_WIDTH-1:0] d_in,
    output logic [DATA_WIDTH-1:0] d_out
);

    // TODO: implement module logic here
    always_ff @(posedge clk) begin
        if (!rst_n)
            d_out <= '0;
        else
            d_out <= d_in;
    end

endmodule
// test_counter.sv — testbench for Counter
//
// Use `$fatal(1, "message")` to signal test failures.
// Use `$finish` at the end so vvp exits cleanly.
// `timescale` belongs here, not in src/.
`timescale 1ns/1ps

module test_counter;

    // -- DUT instantiation ----------------------------------------------------
    localparam int DATA_WIDTH = 8;

    logic                  clk   = 0;
    logic                  rst_n = 0;
    logic [DATA_WIDTH-1:0] d_in  = 0;
    logic [DATA_WIDTH-1:0] d_out;

    counter #(
        .DATA_WIDTH(DATA_WIDTH)
    ) dut (
        .clk   (clk),
        .rst_n (rst_n),
        .d_in  (d_in),
        .d_out (d_out)
    );

    // -- Clock generation -----------------------------------------------------
    always #5 clk = ~clk;   // 100 MHz

    // -- Stimulus and assertions ----------------------------------------------
    initial begin
        // Hold reset
        @(posedge clk); #1;
        rst_n = 0;
        @(posedge clk); #1;

        // Release reset, drive input
        rst_n = 1;
        d_in  = 8'hAB;
        @(posedge clk); #1;

        // Check output registered the input
        if (d_out !== 8'hAB)
            $fatal(1, "FAIL: expected d_out=0xAB, got 0x%02X", d_out);

        $display("PASS: Counter basic register test");
        $finish;
    end

endmodule
// example_usage.sv — Counter
//
// Demonstrates instantiation of counter with non-default parameters.
// Must compile cleanly and exit 0 via $finish.
`timescale 1ns/1ps

module example_usage;

    localparam int DATA_WIDTH = 16;   // 16-bit variant

    logic                   clk   = 0;
    logic                   rst_n = 0;
    logic [DATA_WIDTH-1:0]  d_in  = 0;
    logic [DATA_WIDTH-1:0]  d_out;

    counter #(
        .DATA_WIDTH(DATA_WIDTH)
    ) dut (
        .clk   (clk),
        .rst_n (rst_n),
        .d_in  (d_in),
        .d_out (d_out)
    );

    always #5 clk = ~clk;

    initial begin
        @(posedge clk); #1; rst_n = 0;
        @(posedge clk); #1; rst_n = 1;
        d_in = 16'hBEEF;
        @(posedge clk); #1;
        $display("d_out = 0x%04X (expected 0xBEEF)", d_out);
        $finish;
    end

endmodule
{
  "meta": {
    "id": "rtl-counter-systemverilog",
    "name": "Counter",
    "version": "1.0.0",
    "domain": "rtl",
    "tags": [
      "[TODO: add 3-5 tags]"
    ]
  },
  "description": "[TODO] Describe what Counter does",
  "tech_stack": {
    "language": "systemverilog",
    "dependencies": []
  },
  "custom_notes": "",
  "library_notes": {
    "general": "Single responsibility - one widget does one thing. No global state. No project-specific code, hardcoded paths, credentials, or environment-specific values. Expose variation points as constructor parameters or function arguments - no hardcoded thresholds, colors, sizes, or behavior flags. URLs and endpoints belong in examples as demonstration data, not in src/ - if a widget needs a URL to operate, it must be a parameter the caller provides. All dependencies must be declared in widget.json tech_stack.dependencies. Widgets cannot depend on other widgets - they must be fully self-contained. If you need logic from another widget, copy it into src/ directly. Examples must run and exit cleanly with no user input, no network calls, and no external services or API keys - use fake/hardcoded data. The widget's own declared dependencies are fine and will be installed by the validator before the example runs. Do not modify library_notes - it is managed by Cartograph and will be restored on checkin.",
    "language": "No project-specific names, signal names tied to a particular design, or system identifiers in src/, tests/, or examples/ - use generic RTL names. Use SystemVerilog (.sv) for all files. Testbenches use $fatal(1, \"message\") to signal failures and $finish to exit cleanly \u2014 vvp exits non-zero on $fatal, so it maps directly to test pass/fail. `timescale belongs in testbenches, never in src/. No `initial` blocks, #delays, or $display/$monitor in src/ \u2014 these are simulation-only constructs. Vendor primitives (LUT6, BUFG, ALTPLL, etc.) are blocked unless the vendor library is declared in dependencies \u2014 generic RTL is the default. Use always_ff for sequential logic, always_comb for combinational \u2014 `always @(...)` is blocked; we enforce SystemVerilog idioms. All tunable values (clock frequency, baud rate, data width, address width) must be module parameters with defaults and unit comments. Parameters are the variation points: a consumer should be able to instantiate your module with different parameters without touching source. Reset must be a parameter-defined polarity (active-high or active-low) with synchronous behavior as the default. No hardcoded sizes or widths \u2014 everything that varies by use case must be a parameter. $readmemh/$readmemb file paths must be parameters, not hardcoded strings.",
    "domain": "Every timing constant (clock frequency, baud rate, bit period) and bus width must be a module parameter with a default and a unit comment (// Hz, // bits, // bytes). Never hardcode these \u2014 a consumer must be able to instantiate your module at any clock frequency or bus width by changing parameters only. Module names must be nouns or noun phrases describing the hardware function (uart_tx, spi_master, gray_encoder) \u2014 not verbs. All parameters must be synthesizable types (int, logic, bit) \u2014 no real, string, or event. The example must compile cleanly and simulate to $finish with vvp. Write testbenches to be self-contained: include all required src files via the compile command, assert expected behavior, and terminate with $finish."
  }
}