File Naming Conventions in Zakirullin Files: Rules and Best Practices

In Zakirullin Files, the filename (including the .md extension) serves as the unique identifier for every document, acting as the primary key for storage, synchronization, and UI display across all platforms.

Zakirullin Files is an open-source, Markdown-based knowledge management system that stores all data as plain text files. Understanding the file naming conventions is essential for maintaining compatibility between the web interface and Go-based back-end while ensuring reliable cross-platform synchronization.

The Filename as Unique Identifier

In zakirullin/files.md, the filename itself functions as the primary key for every document. According to README.md, the system treats the filename (e.g., note.md) as the unique ID when locating, synchronizing, and linking files. This design eliminates the need for database indices or UUIDs, keeping the architecture portable and simple.

When the back-end processes a file, it extracts the filename from the path and uses it for all subsequent operations:

// Example of creating a new file (server side)
func (fs *FS) Put(path string, content []byte) error {
    filename := toFilename(path)                // e.g. "note.md"
    if strings.TrimSpace(filename) == "" {
        return errors.New("filename cannot be empty")
    }
    // The filename is the unique identifier for the file
    // …
}

One-Level Directory Nesting

The application enforces a strict one-level nesting policy to simplify path handling. A file is uniquely identified by the combination of its directory and filename, where the directory is either the root (/) or a predefined top-level folder such as brain/, journal/, or habits/.

This constraint, documented in README.md, prevents complex recursion issues in both the client and server code. The file-to-path index in web/files.js relies on this flat structure to build efficient lookup tables without traversing deep directory trees.

File Extensions and Type Handling

All content files must use the .md extension to ensure the Markdown parser can process them correctly. Non-Markdown assets such as images, videos, and other media files must reside in the dedicated media/ folder and retain their original extensions (e.g., .png, .jpg).

This separation guarantees that the sync engine and UI renderer can distinguish between editable notes and static attachments without inspecting file contents.

Forbidden Characters and Sanitization

To ensure cross-platform compatibility across Windows, macOS, and Linux, the system strips specific characters from all user-provided filenames. In web/lib/fs.js, the sanitizeFilename function removes the following prohibited characters: < > : " | \ ? * \0 /.

// web/lib/fs.js – sanitising a filename before any filesystem operation
const FORBIDDEN_FILENAME_CHARS = ['<', '>', ':', '"', '|', '\\', '?', '*', '\x00', '/'];
function sanitizeFilename(filename) {
    // Remove all prohibited characters
    return FORBIDDEN_FILENAME_CHARS.reduce(
        (result, ch) => result.replaceAll(ch, ''), filename);
}

This sanitization runs automatically during every rename or create operation, preventing filesystem errors when files are saved to Windows drives or cloud storage services with strict naming rules.

ASCII-Only Policy and Encoding

While the system supports Unicode, non-ASCII characters are discouraged in filenames. When present, users must disable quoting (as documented in docs/your-own-server.md) to prevent encoding issues during API transfers that expect URL-safe strings.

For maximum compatibility, the documentation recommends using descriptive, short, ASCII-only names that are easy to type and share across different operating systems.

Uniqueness Constraints

Filenames must be unique within their directory, with enforcement performed case-insensitively. The system does not allow two files with identical names (such as Note.md and note.md) to exist in the same folder.

This rule, implemented in the synchronization logic, guarantees deterministic lookups and prevents collision errors during rename operations. The sync engine detects changes by comparing header-derived filenames with actual file paths, as detailed in docs/sync-flow.md.

Header Generation from Filenames

The display header for each file is automatically derived from its filename by stripping the .md extension and capitalizing the first letter. For example, note.md becomes Note in the UI navigation and linking system.

This convention ensures consistency between the filesystem representation and the user-facing interface without requiring separate metadata files or frontmatter.

Practical Naming Patterns

The repository recommends descriptive, human-readable names following these common patterns:

  • Chat.md – Central conversation log
  • brain/Note.md – Knowledge note in the "brain" category
  • journal/2024.08 August.md – Dated journal entry with period notation
  • habits/Ate consciously.md – Habit tracking file
  • media/photo.png – Attached image asset

These patterns support a Zettelkasten-style workflow while maintaining the simplicity required by the flat file structure.

Summary

  • Filename as ID: The filename (including .md) serves as the unique primary key for all storage and sync operations in zakirullin/files.md.
  • One-level nesting: Files reside either in the root or in specific top-level directories like brain/ or journal/, with no subdirectories allowed.
  • Extension requirement: Content files must end with .md, while media files belong in media/ with original extensions.
  • Character sanitization: The sanitizeFilename function in web/lib/fs.js automatically removes characters like <, >, :, ", |, \, ?, *, \0, and /.
  • Uniqueness: Duplicate filenames (case-insensitive) are prohibited within the same directory to prevent collision errors.
  • Header derivation: UI display names are generated by removing the extension and capitalizing the first letter of the filename.

Frequently Asked Questions

What characters are forbidden in Zakirullin Files filenames?

The system automatically strips the following characters from all filenames: less-than (<), greater-than (>), colon (:), double quote ("), pipe (|), backslash (\), question mark (?), asterisk (*), null byte (\0), and forward slash (/). This sanitization occurs in web/lib/fs.js to ensure compatibility with Windows, macOS, and cloud storage providers.

How does Zakirullin Files handle file organization and subdirectories?

The application supports only one level of directory nesting. Files can exist in the root directory or in predefined top-level folders such as brain/, journal/, or habits/. The system identifies each file by the pair (directory, filename), simplifying path resolution in both the web client and Go back-end.

Why must Markdown files use the .md extension in Zakirullin Files?

The .md extension is mandatory for content files because the system relies on this suffix to identify parseable Markdown documents. This distinction allows the sync engine to separate editable text files from media assets, which must be stored in the media/ directory with their original extensions preserved.

How are display titles generated from filenames in the UI?

The web interface generates headers by removing the .md extension and capitalizing the first character of the remaining string. For example, a file named project-ideas.md displays as Project-ideas in the navigation. This convention ensures consistency between the filesystem and the user interface without requiring separate metadata files.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →