# How Archify Generates Stable Link Anchors for Navigation

> Learn how Archify generates stable link anchors for navigation using slugified names and UUID hashes. Ensure your deep links remain intact even after code changes.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: how-to-guide
- Published: 2026-08-31

---

**Archify creates deterministic, human-readable HTML anchors by combining slugified node names with UUID-derived hashes, ensuring deep links survive code changes.**

Stable link anchors are essential for navigating large architecture diagrams. In the `tt-a1i/archify` codebase, every rendered node receives a unique anchor that remains constant across builds—enabling reliable deep-linking from documentation, tickets, and external tools.

## Core Mechanics of Archify's Anchor Generation

Archify generates stable anchors through a five-step pipeline implemented across its renderer modules.

### Step 1: Normalize the Target Name

The first step converts human-readable node names into URL-friendly slugs. The `slugify(name)` function in [`archify/renderers/markdown-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/markdown-utils.js) handles this transformation:

- Converts to lowercase
- Replaces spaces and punctuation with dashes
- Removes special characters

A node named **"User Profile Component"** becomes `user-profile-component`.

### Step 2: Create a Deterministic Hash

To prevent collisions when multiple nodes share the same display name, Archify appends a short hash derived from the node's stable UUID. The `stableHash(uuid)` function in [`archify/renderers/anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/anchor-utils.js) computes this:

- Takes an SHA-1 digest of the UUID
- Truncates to six hexadecimal characters

This guarantees uniqueness without sacrificing determinism.

### Step 3: Assemble the Final Anchor

The `makeAnchor(node)` function in [`archify/renderers/anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/anchor-utils.js) combines both parts:

```

<slug>-<hash>

```

For example: `user-profile-component-a1b2c3`

This string becomes the HTML `id` attribute.

### Step 4: Inject Into Rendered Output

Each renderer calls `makeAnchor(node)` before emitting markup. In [`archify/renderers/workflow/index.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/workflow/index.js), the anchor is inserted directly into the rendered element:

```js
import { renderNode } from 'archify/renderers/workflow';
import { makeAnchor } from 'archify/renderers/anchor-utils';

const node = {
  id: 'c9f8a7e4-1234-5678-90ab-cdef12345678',
  name: 'User Profile Component',
};

const anchor = makeAnchor(node);  // "user-profile-component-a1b2c3"
const html = renderNode(node, { id: anchor });

console.log(html);
// <div id="user-profile-component-a1b2c3" class="node">…</div>

```

### Step 5: Resolve Links at Runtime

Browser-native anchor handling takes over. Clicking `#user-profile-component-a1b2c3` scrolls directly to the element. No additional JavaScript is required.

## Why This Design Works

**Determinism** — Both the slug and hash are pure functions. The same inputs always produce the same output, eliminating randomness that could break links.

**Collision-resistance** — The six-character hash provides 16.7 million possible suffixes, ensuring unique anchors even for identically named nodes.

**Human-readability** — The slug component preserves context. Links like `#user-profile-component-a1b2c3` are self-documenting unlike opaque hashes alone.

**Stability across builds** — Since anchors derive from the node's UUID (stored in [`archify/skill-release.json`](https://github.com/tt-a1i/archify/blob/main/archify/skill-release.json) and workflow definitions), they persist through code refactors, renames, and render pipeline updates.

## Using Stable Anchors in Documentation

Once rendered, these anchors enable reliable deep-linking:

```markdown

# Architecture Overview

The **User Profile Component** is rendered below.

You can link directly to it:
[Jump to component](#user-profile-component-a1b2c3)

```

Teams embed these anchors in README files, Jira tickets, Confluence pages, or Slack messages—confident the links will resolve correctly after future Archify runs.

## Key Implementation Files

| File | Purpose |
|------|---------|
| [`archify/renderers/markdown-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/markdown-utils.js) | `slugify()` — normalizes display names |
| [`archify/renderers/anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/anchor-utils.js) | `stableHash()` and `makeAnchor()` — generates deterministic anchors |
| [`archify/renderers/workflow/index.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/workflow/index.js) | Integrates anchors into workflow diagram markup |
| `archify/bin/archify.mjs` | CLI entry point orchestrating the render pipeline |

## Summary

- Archify stable link anchors combine **slugified names** with **UUID-derived hashes** for uniqueness
- The implementation spans [`anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/anchor-utils.js) and [`markdown-utils.js`](https://github.com/tt-a1i/archify/blob/main/markdown-utils.js) with renderer-specific integration
- Anchors survive code changes because they derive from stable node UUIDs, not volatile properties
- Browser-native handling requires no runtime JavaScript
- The CLI in `archify.mjs` drives the entire pipeline end-to-end

## Frequently Asked Questions

### How does Archify prevent anchor collisions between nodes with identical names?

Archify appends a six-character hash from `stableHash(uuid)` in [`archify/renderers/anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/anchor-utils.js). Even if two nodes share the display name "Service", their different UUIDs guarantee unique suffixes like `service-a1b2c3` versus `service-d4e5f6`.

### Where are stable anchors stored in the output HTML?

The `makeAnchor(node)` function returns the final string, which renderers pass as the `id` attribute. In [`archify/renderers/workflow/index.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/workflow/index.js), this becomes `<div id="user-profile-component-a1b2c3">` or equivalent markup depending on the output format.

### Do anchors change when I rename a node?

**Yes**—the slug portion derives from the display name, so renaming alters the anchor. However, the UUID remains constant, so downstream tools tracking by UUID can detect and update references. For fully immutable anchors, Archify would need to store historical slug mappings.

### Can I customize the hash length or format?

The current implementation in [`archify/renderers/anchor-utils.js`](https://github.com/tt-a1i/archify/blob/main/archify/renderers/anchor-utils.js) hardcodes six-character SHA-1 truncation. To modify this, override `stableHash()` or inject a custom anchor generator before the rendering phase in your workflow renderer.