# velotype's portable app bundle installs a CLI symlink that moving it destroys

> A Rust and GPUI Markdown editor with rendered and source editing modes, exported as one executable. Its parser silently falls back to raw Markdown when it is unstable, the macOS .app install needs an administrator password to create a symlink that breaks as soon as the bundle is moved, and the default feature set turns on sixteen tree-sitter grammars with one declared twice.

**manyougz/velotype** — Write at the speed of thought – Velotype is a high-performance native Markdown editor built with Rust and GPUI.⚡

- Repository: https://github.com/manyougz/velotype
- Stars: 581 · Forks: 55
- Language: Rust
- License: NOASSERTION
- Published: 2026-09-20 · Updated: 2026-09-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/manyougz-velotype

## Moving Velotype.app silently breaks the velotype command

The macOS install has two options and the documentation's warning lands on the one it does not recommend. Option 1 is the app package: download `velotype-*.zip`, unzip to get `Velotype.app`, drag it to `/Applications` or anywhere, double-click. Option 2 is the PKG installer, marked recommended: download `velotype-*.pkg`, double-click, and it installs to `/Applications` and configures the command line tool `velotype` automatically, with the symlink managed by the installer's `postinstall` and `preuninstall` scripts. The app package gets the same command only through the menu, Help then Install CLI Command, followed by an administrator password. And then: if you move or delete `Velotype.app`, the symlink becomes invalid and running `velotype` reports command not found. So the option advertised as requiring no installation is the one that leaves a system-wide entry pointing at a path you are invited to move, and it asks for admin rights to create it. Windows and Linux have no equivalent step at all: the release is a `.zip` or `.tar.gz` you unzip and run, with no CLI registration and nothing left behind.

## The parser falls back to raw Markdown when it is unstable

One line in the feature list carries more weight than the rest. Rust drives parsing, state updates and rendering, and the parser follows a standard-oriented strategy and falls back to raw Markdown in unstable cases. In an editor whose headline is instant rendered editing, that is a silent mode switch: a document that defeats the parser stops being rendered and becomes source text, with no error. The block model around it is what makes the round trip coherent. Markdown structure is represented as editable blocks, which the documentation credits with keeping document structure clear and controllable without a preview-pane synchronization loop, and the architecture section confirms a native block tree as the runtime model: stable supported Markdown is converted into structured blocks on import and the block tree is serialised on save. The visible text stops mid-sentence on that save path, which is the one detail here a reader has to confirm for themselves. The syntax coverage claimed alongside it is broad: headings, paragraphs, lists, task lists, quotes, callouts, tables, code blocks, inline formatting, links, reference-style links and images, footnotes, standalone images, comment blocks, and safe native HTML handling.

## Four default features pull in sixteen tree-sitter grammars, and html is declared twice

The feature table in the manifest explains the size of a default build. `default` enables `code-highlight-core`, `code-highlight-official`, `code-highlight-config` and `html-native`. The official set alone names sixteen grammars: Rust, JavaScript, TypeScript, JSON, Markdown, Bash, C, C++, C#, CSS, Go, HTML, Java, PHP, Python and Ruby. The config set adds YAML and TOML. That is eighteen grammars in the default configuration, with no documented minimal set to turn most of them off. One detail in the same block is a plain duplication: `tree-sitter-html` appears under `html-native` and again inside `code-highlight-official`, so the same grammar is declared by two separate features. Cargo resolution will de-duplicate it, so the effect is on the feature graph rather than on the binary, but it means the two features are not independent of each other in the way the table implies. The non-grammar dependencies are few by comparison: anyhow, base64, uuid, unicode-segmentation and serde, alongside GPUI itself pinned at version 0.2 with a `runtime_shaders` feature enabled.

## An empty base_theme_id inherits the dark theme, not the light one

Theme customisation is partial by design, which is what lets a theme file be tiny. Missing fields or empty values inherit from a built-in base theme named by the theme pack, either `velotype` or `velotype-light`, following the `base_theme_id` field. The fallback sentence is the one to note: when that field is empty or invalid, it falls back to the `velotype` theme values. So a light theme that forgets to set `base_theme_id` silently inherits the dark palette rather than the light one, and the result will look wrong in a way that is easy to misread as a bug in your own JSON. Language packs use the same partial strategy, with missing strings falling back to English and imported packs normalised before being written into the app configuration directory. On formats, JSONC comments are accepted for writing and sharing, while the normalised files the app saves are strict JSON, so a commented example will not stay commented once imported. The overridable set is correspondingly wide, covering global colours, fonts, sizes, menus, dialogs, table controls, image placeholders, code highlighting colours and layout tokens, and the project attaches its own stability warning to that surface: it says the project is evolving rapidly so theme field changes may occur frequently.

## Twelve clippy lints are allowed, three of them correctness-adjacent

The manifest silences twelve clippy lints by name, and the comment above the block explains why: they mirror the spirit of a workspace lint set elsewhere, categorically silencing noise such as range-loop indexing, identical-block flagging, helper argument counts and futures detached with a let, while keeping real correctness lints active. Most of the list fits that description, since `if_same_then_else`, `needless_range_loop`, `too_many_arguments`, `module_inception`, `collapsible_if` and `collapsible_else_if` are style or readability. Three are less obviously noise: `manual_div_ceil`, `manual_checked_ops` and `manual_clamp` point at places where hand-written arithmetic or unchecked conversion can go wrong. Whether that is the right line is a project judgement rather than a defect, but it is a line, and the comment claims a stricter one than the list draws.

## Remote images load over the network, hosting them is still an open box

The architecture table lists eight layers, and one of them is a network client. `net` is described as HTTP client integration for remote image loading, which is what allows a document to reference an image by URL. The roadmap then lists built-in image hosting as an unchecked box. So the asymmetry is deliberate: images are fetched from elsewhere, and putting them somewhere is not yet implemented. Two other entries in the same list are open, one of them more complete IME behaviour, which matters for the CJK users the project partly serves, since the README itself links a Chinese translation at `docs/README.zh-CN.md` and the i18n layer handles system locale matching and runtime language selection. Export is the tidier story: HTML export maps the active theme into CSS, and PDF export reuses that same themed HTML pipeline so the two stay visually consistent.

## A test.md in the root, no tests directory, and a month between tag and push

The repository top level is `.github/`, `.gitignore`, `Cargo.lock`, `Cargo.toml`, `LICENSE-APACHE`, `README.md`, `assets/`, `benches/`, `build.rs`, `docs/`, `resources/`, `scripts/`, `src/` and `test.md`. Two things stand out. There is a `benches/` directory and no `tests/` directory, and the one file whose name suggests testing is a Markdown document sitting in the root. And the licence story needs two sources read together: the repository's own licence field records nothing, while the manifest declares Apache-2.0 and the tree carries a matching `LICENSE-APACHE`. On versions, the manifest reads 0.7.2 and the newest tag is v0.7.2 from 2026-08-14, but the last push is dated 2026-09-15, so the default branch is about a month past the last release. Building from source needs Git, Cargo and a Rust toolchain with 2024 edition support, plus whatever native build dependencies GPUI and the system toolchain require:

```bash
git clone https://github.com/manyougz/velotype.git
```

```bash
cargo build --release
```

The artifact lands under `target/release` and can be run directly. On Windows and Linux the release path is equally manual: download the `.zip` or `.tar.gz`, unzip it, and run the executable. Two smaller details sit in the same header, a link to the features anchor that appears twice in the badge row, and a second README in Chinese at `docs/README.zh-CN.md` alongside the English one.

## Conclusion

Use velotype if you want a rendered Markdown editor that is a native binary rather than a web view, and if you install from the PKG on macOS rather than dragging the app bundle around. Do not adopt it on the strength of the portability claim without reading the install section, because the app bundle route asks for an administrator password to place a `velotype` symlink that a later move or delete of `Velotype.app` silently invalidates. Before you build on a theme, read the inheritance rule, since an empty or invalid `base_theme_id` resolves to the dark `velotype` values rather than to light ones. And expect the fallback: the parser is described as dropping to raw Markdown in unstable cases, so verify the round trip on your own documents before you trust the rendered mode.

## FAQ

### How do I install velotype on macOS?

Two ways. The PKG installer, marked recommended, downloads `velotype-*.pkg`, installs to `/Applications` and configures the `velotype` command automatically through its `postinstall` and `preuninstall` scripts. The app package unzips to `Velotype.app`, needs no installer, and gets the CLI only through Help then Install CLI Command with an administrator password.

### What happens if I move the velotype app bundle on macOS?

The `velotype` symlink becomes invalid and the command reports not found. The documentation warns about this specifically for the app package route, which is why the PKG installer is the recommended option: it manages the symlink automatically through its own install and uninstall scripts.

### Does velotype need a web view or an Electron shell?

No. It renders natively through GPUI and explicitly does not depend on Electron, Tauri or any WebView shell. Rust drives parsing, state updates and rendering, and after compilation the application is a single executable file that targets Windows, Linux and macOS.

### How do I import a custom theme into velotype?

Use Theme then Add Theme Config in the app to import a `.json` or `.jsonc` file, starting from the example at `assets/custom-theme.example.jsonc`. JSONC comments are accepted when writing and sharing, but the normalised file the app writes into its configuration directory is strict JSON. An empty or invalid `base_theme_id` falls back to the dark `velotype` values.

### What are velotype's main open roadmap items?

Built-in image hosting and more complete IME behaviour. Remote images already load through the `net` layer, which is an HTTP client integration, so images can be referenced by URL but not yet hosted by the app. Two roadmap items are already ticked: optimising parsing and rendering for extremely large documents, and workspace mode with outline parsing.

## Sources

- [Issues](https://github.com/manyougz/velotype/issues)
- [manyougz/velotype on GitHub](https://github.com/manyougz/velotype)
- [README](https://github.com/manyougz/velotype/blob/main/README.md)
- [Releases](https://github.com/manyougz/velotype/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/manyougz-velotype
