Example specs

How Tessl's specification documents are formatted, with some examples.

👉 Closed beta notice

The full framework is currently part of Tessl’s closed beta program. You can request access here.

Specifications ('specs') are markdown documents that define the requirements and behavior of software modules in Tessl's AI Native Development approach. They serve as the single source of truth for what your code should do, and Tessl uses them to generate both implementation code and tests. They should have a .spec.md file extension.

A spec describes:

  • What the module does (capabilities and behavior)

  • How to verify it works correctly (test definitions)

  • How it should be used (API)

  • What dependencies it needs (if any)

  • Where its corresponding code files live

A spec may also include incidental implementation details inferred by AI. These weren’t stated by a human author but are needed for stable code generation. For example, a “tic-tac-toe game” spec might include that the board is 3x3.


Minimal specification example

An absolutely minimal specification document might look like this:

- It adds two numbers together [@test](../test/add.test.js)

```javascript { .api }
function add(a, b) {
  // IMPLEMENTATION HERE
}
module.exports = { add };
```

There are two important things here:

  • A magic @test link inside a List Item - this is considered a test definition

  • A code block with the ID api - this is considered the API

More detailed specification example

A slightly more complete specification document for the above might look like this

# Big Math

A simple math library with Big Int support

## Capabilities

### Addition

- It adds two numbers together [@test](../test/add.test.js)
- It throws an exception when adding `NaN` [@test](../test/add_nan.test.js)
- It returns `Infinity` when adding `Infinity` [@test](../test/add_inf_impl.test.js) { .impl }

### Subtraction

- It subtracts a number from another number [@test](../test/subtract.test.js)
- It throws an exception when subtracting `NaN` [@test](../test/subtract_nan.test.js)
- It returns `-Infinity` when subtracting `Infinity` [@test](../test/sub_inf_impl.test.js) { .impl }
- It returns `NaN` when subtracting `Infinity` from `Infinity` [@test](../test/sub_inf_nan_impl.test.js) { .impl }

## API

[@generate](./src/index.js)

```javascript { .api }
function add(a, b) {
  // IMPLEMENTATION HERE
}
function subtract(a, b) {
  // IMPLEMENTATION HERE
}

module.exports = { add, subtract };
```

## Dependencies { .dependencies }

### big-int { .dependency }

Provides Big Int support

[@use](./big-int/spec.md)

## Style requirements

The guidelines in the [externally published library standards](path/to/some/other/text/file) document should be observed.

The hierarchy is decided by the author, with no requirement to use specific words or headings.

Context is inferred from this hierarchy. The example above translates to:

Big Math
├── Capabilities
│ ├── Addition
│ └── Subtraction
├── API
└── Dependencies
  └── big-int

This example also shows our second "magic" link [@use], our third 'magic' link [@generate] and another meaningful class { .dependency } .

Elaborate specification example

Another specification document might look like this:

# Base58 Encoder/Decoder

A library for encoding data into Base58 and decoding Base58 strings back into their original binary formats.

Use cases are outlined in [this document](path/to/another/text/file).

## Capabilities

### Validates input for encoding

- Passing a non-Buffer or non-Uint8Array (e.g., a string "data") to the encode function throws an error. [@test](../test/invalid_encode_input.test.js)
- Passing a null or undefined value to the encode function throws an error. [@test](../test/null_encode_input.test.js)

### Validates input for decoding

- Passing a non-string (e.g., a number 12345) to the decode function throws an error. [@test](../test/invalid_decode_input.test.js)
- Passing an invalid Base58 string (e.g., containing characters not supported by Base58) to the decode function throws an error. [@test](../test/invalid_characters_decode.test.js)

### Encodes binary data to Base58

- Given a Buffer containing known binary data, the encode function returns the expected Base58 string. [@test](../test/encode_known_input.test.js)
- Encoding an empty Buffer returns an empty string. [@test](../test/encode_empty_buffer.test.js)

### Decodes Base58 strings to binary data

- Given a valid Base58 string corresponding to known binary data, the decode function returns the expected Buffer. [@test](../test/decode_known_input.test.js)
- Decoding an empty string returns an empty Buffer. [@test](../test/decode_empty_string.test.js)

### Protocol and error nuance { .impl }

- Decoding tolerates ASCII whitespace (spaces, tabs, newlines) and underscores anywhere in the input; they are ignored. [@test](../test/decode_ignores_ws_impl.test.js)
- Encoding does not introduce redundant leading `1` characters; if the input has no leading `0x00` bytes, the output must not start with `1`. [@test](../test/encode_no_redundant_leading_ones_impl.test.js)
- When the decoder encounters an invalid character, the thrown error message begins with `Invalid Base58 character at offset` and includes the numeric offset. [@test](../test/decode_error_message_format_impl.test.js)

## API

[@generate](./src/index.js)

```javascript { .api }
/**
 * Encodes binary data (Buffer or Uint8Array) into a Base58 string.
 *
 * @param {Buffer|Uint8Array} data - The binary data to encode.
 * @returns {string} The Base58 encoded representation of the input data.
 * @throws {Error} Throws an error if the provided data is not a Buffer or Uint8Array.
 */
function encode(data) {
  // IMPLEMENTATION HERE
}

/**
 * Decodes a Base58 string back into its original binary data (Buffer).
 *
 * @param {string} base58Str - The Base58 string to decode.
 * @returns {Buffer} The decoded binary data.
 * @throws {Error} Throws an error if the provided string is not a valid Base58 encoded string.
 */
function decode(base58Str) {
  // IMPLEMENTATION HERE
}

module.exports = {
  encode,
  decode,
};
```

## Dependencies { .dependencies }

### Encoder { .dependency }

Encodes data into Base58 format

[@use](./encoder/spec.md)

### Decoder { .dependency }

[@use](./decoder/spec.md)

Decodes Base58 strings back into data

Last updated