Technical writing on Linux infrastructure, execution systems, financial data pipelines, and the operational software built and run in-house at Gratice.
We write about software built with the same rigour applied to our own trading infrastructure. Systems designed for operational clarity, long-term maintainability, and full ownership.
We do not rely on third-party frameworks where a simpler, more robust solution exists. Complexity is a liability. These notes document what we actually build and run.
Notes, essays, and field observations from systems built for environments where correctness and performance are non-negotiable.
Selected notes from operational work. Written for engineers who prefer precision over abstraction.
A single configuration file shared between Vim, Neovim, and VSCode Neovim (Cursor). Environment detection via g:vscode splits terminal and editor behaviour cleanly.
"*****************************************************************************
" .vimrc
"
" Copyright (c) 1993-2026 Gratice LLC. All rights reserved.
"
" Author: Yutaka TOMII
" Company: Gratice LLC
"
" This vimrc has been refined since 1993, originally written for BSDi,
" then continuously evolved through FreeBSD and beyond.
" Compatible with Vim, Neovim, and VSCode Neovim extension (Cursor).
"
" Last updated: April 18, 2026
"
" [VSCode/Cursor Setup]
" 1. Install Neovim >= 0.10.0
" macOS: brew install neovim
" Linux: apt install neovim
" 2. Install VSCode Neovim extension: asvetliakov.vscode-neovim
" 3. Add to Cursor/VSCode settings.json:
" "vscode-neovim.neovimExecutablePaths.darwin": "/opt/homebrew/bin/nvim"
" "vscode-neovim.neovimExecutablePaths.linux": "/usr/bin/nvim"
" 4. Create ~/.config/nvim/init.vim:
" set runtimepath^=~/.vim runtimepath+=~/.vim/after
" let &packpath = &runtimepath
" source ~/.vimrc
"*****************************************************************************
"*****************************************************************************
" Vim-Plug bootstrap
"*****************************************************************************
let vimplug_exists=expand('~/.vim/autoload/plug.vim')
if !filereadable(vimplug_exists)
echo "Installing Vim-Plug..."
silent exec "!curl -fLo " . shellescape(vimplug_exists) . " --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
if !isdirectory(expand('~/.vim/undodir'))
call mkdir(expand('~/.vim/undodir'), "p", 0700)
endif
call plug#begin(expand('~/.vim/plugged'))
"-----------------------------------------------------------------------------
" Plugins: work in both Vim and VSCode
" [Cursor side] VSCode Neovim extension handles these automatically.
" No additional setup required unless noted.
"-----------------------------------------------------------------------------
" --- Core editing ---
Plug 'tpope/vim-commentary' " gcc to comment/uncomment lines
Plug 'tpope/vim-dispatch' " async build and test dispatch
Plug 'tpope/vim-surround' " cs"' ysiw" ds" to manipulate surrounds
Plug 'tpope/vim-repeat' " repeat plugin actions with .
Plug 'junegunn/vim-easy-align' " ga= to align by delimiter
Plug 'moll/vim-bbye' " :Bdelete without closing window
Plug 'AndrewRadev/splitjoin.vim' " gS / gJ to split/join lines
Plug 'stephpy/vim-yaml' " improved YAML syntax
" --- Language syntax ---
" VSCode handles LSP and completion via extensions (noted per language).
" These plugins add syntax highlighting and indentation rules only.
Plug 'mattn/emmet-vim' " HTML/CSS abbreviation expansion (Ctrl+Y,)
" [Cursor] No extra extension needed
Plug 'hail2u/vim-css3-syntax' " CSS3 syntax improvements
Plug 'leafgarland/typescript-vim' " TypeScript syntax
" [Cursor] Install: ESLint (dbaeumer.vscode-eslint)
" Install: Prettier (esbenp.prettier-vscode)
Plug 'posva/vim-vue' " Vue.js single-file component syntax
" [Cursor] Install: Volar (vue.volar)
Plug 'JuliaLang/julia-vim' " Julia syntax and indentation
" [Cursor] Install: julia-vscode (julialang.language-julia)
Plug 'guns/vim-clojure-static' " Clojure syntax
Plug 'benknoble/vim-sexp' " S-expression structural editing
Plug 'tpope/vim-sexp-mappings-for-regular-people' " friendlier sexp keymaps
" [Cursor] Install: Calva (betterthantomorrow.calva)
Plug 'udalov/kotlin-vim' " Kotlin syntax
" [Cursor] Install: Kotlin (fwcd.kotlin)
Plug 'derekwyatt/vim-scala' " Scala syntax
" [Cursor] Install: Metals (scalameta.metals)
Plug 'zah/nim.vim' " Nim language syntax
" [Cursor] Install: NimVSCode (nimsaem.nimvscode)
Plug 'vim-pandoc/vim-pandoc-syntax' " Pandoc-flavored Markdown syntax
Plug 'quarto-dev/quarto-vim' " Quarto document syntax
" [Cursor] Install: Quarto (quarto.quarto)
Plug 'benknoble/vim-racket' " Racket syntax
Plug 'elixir-editors/vim-elixir' " Elixir syntax
" [Cursor] Install: ElixirLS (jakebecker.elixir-ls)
Plug 'kaarmu/typst.vim' " Typst document syntax
" [Cursor] Install: Typst LSP (nvarner.typst-lsp)
Plug 'plasticboy/vim-markdown' " enhanced Markdown syntax
Plug 'rhysd/reply.vim' " REPL integration for various languages
Plug 'bakpakin/janet.vim' " Janet language syntax
Plug 'ocaml/vim-ocaml' " OCaml syntax, indentation, and ftplugin
" [Cursor] Install: OCaml Platform
" (ocamllabs.ocaml-platform)
" Requires opam packages:
" opam install ocaml-lsp-server ocamlformat
" --- Colorschemes ---
Plug 'morhetz/gruvbox'
Plug 'wesQ3/wombat.vim'
"-----------------------------------------------------------------------------
" Plugins: Vim / Neovim terminal only
" Excluded in VSCode because VSCode provides equivalent built-in features.
" [Cursor side] Install the noted extension from the Extensions panel (Ctrl+Shift+X).
"-----------------------------------------------------------------------------
if !exists('g:vscode')
" --- File management / UI ---
Plug 'preservim/nerdtree' " [Cursor] Built-in Explorer (Ctrl+Shift+E)
Plug 'jistr/vim-nerdtree-tabs' " [Cursor] Built-in Explorer
Plug 'vim-airline/vim-airline' " [Cursor] Built-in status bar
Plug 'vim-airline/vim-airline-themes' " [Cursor] Built-in status bar
Plug 'airblade/vim-gitgutter' " [Cursor] Install: GitLens (eamodio.gitlens)
Plug 'nathanaelkane/vim-indent-guides' " [Cursor] Settings: editor.guides.indentation: true
Plug 'liuchengxu/vim-which-key' " [Cursor] Command Palette (Ctrl+Shift+P)
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } " [Cursor] Quick Open (Ctrl+P)
Plug 'junegunn/fzf.vim' " [Cursor] Quick Open (Ctrl+P)
Plug 'vifm/vifm.vim' " [Cursor] Built-in Explorer
Plug 'junegunn/goyo.vim' " [Cursor] No direct equivalent
Plug 'junegunn/limelight.vim' " [Cursor] No direct equivalent
" --- LSP / Completion / Linting ---
Plug 'davidhalter/jedi-vim' " [Cursor] Install: Python (ms-python.python)
Plug 'dense-analysis/ale' " [Cursor] Install per language:
" Shell: ShellCheck (timonwong.shellcheck)
" Python: Ruff (charliermarsh.ruff)
" JS/TS: ESLint (dbaeumer.vscode-eslint)
" Go: bundled in golang.go extension
" Rust: bundled in rust-analyzer
Plug 'github/copilot.vim' " [Cursor] Install: GitHub Copilot (github.copilot)
" Cursor Pro includes Copilot-equivalent built-in
Plug 'SirVer/ultisnips' " [Cursor] Built-in snippet support
Plug 'easymotion/vim-easymotion' " [Cursor] Requires VSCode-specific fork:
" asvetliakov.vscode-easymotion
" --- Language tooling ---
Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }
" [Cursor] Install: Go (golang.go)
" Run: Go: Install/Update Tools after install
Plug 'rust-lang/rust.vim' " [Cursor] Install: rust-analyzer (rust-lang.rust-analyzer)
Plug 'racer-rust/vim-racer' " [Cursor] Bundled in rust-analyzer
Plug 'kdheepak/JuliaFormatter.vim' " [Cursor] Bundled in julia-vscode extension
Plug 'venantius/vim-cljfmt' " [Cursor] Bundled in Calva extension
" --- Document authoring ---
Plug 'iamcco/markdown-preview.nvim', { 'do': { -> mkdp#util#install() }, 'for': ['markdown', 'vim-plug']}
" [Cursor] Install: Markdown Preview Enhanced
" (shd101wyy.markdown-preview-enhanced)
Plug 'dhruvasagar/vim-table-mode', { 'on': 'TableModeEnable' }
Plug 'mattn/vim-maketable'
Plug 'lervag/vimtex' " [Cursor] Install: LaTeX Workshop
" (james-yu.latex-workshop)
" Requires: TeX Live or MiKTeX installed
Plug 'xuhdev/vim-latex-live-preview' " [Cursor] Bundled in LaTeX Workshop
Plug 'reedes/vim-pencil'
Plug 'reedes/vim-lexical'
Plug 'reedes/vim-wordy'
endif
call plug#end()
"*****************************************************************************
" General settings
"*****************************************************************************
" Encoding
set encoding=utf-8
set fileencoding=utf-8
set fileencodings=utf-8,ucs-bom,euc-jp,cp932
" Display
syntax on
set number relativenumber cursorline showcmd showmatch laststatus=2 wildmenu visualbell
" Indentation
set autoindent smartindent tabstop=4 shiftwidth=4 expandtab smarttab
" Search
set hlsearch incsearch ignorecase smartcase
" System
set nobackup noswapfile autoread hidden clipboard=unnamedplus undofile
set undodir=~/.vim/undodir
" Performance
set lazyredraw
" Folding
set foldmethod=indent
set foldlevelstart=99
"*****************************************************************************
" Colorscheme
"*****************************************************************************
set background=dark
let g:gruvbox_contrast_dark = 'medium'
try
colorscheme gruvbox
catch /^Vim\%((\a\+)\)\=:E185/
colorscheme default | set background=dark
endtry
"*****************************************************************************
" Key mappings: common (both Vim and VSCode)
"*****************************************************************************
let mapleader=','
" Redo with U
nnoremap U <C-r>
" Close buffer without closing window (bbye)
nnoremap <Leader>q :Bdelete<CR>
" Save / reload vimrc
nnoremap <leader>w :w<CR>
cnoremap w!! w !sudo tee % > /dev/null
nnoremap <leader>vS :source $MYVIMRC<CR>:echo 'vimrc reloaded'<CR>
" Clipboard
vnoremap <leader>y "+y
nnoremap <leader>Y "+Y
nnoremap <leader>p "+p
nnoremap <leader>P "+P
" Window resize
nnoremap <leader>> :vertical resize +5<CR>
nnoremap <leader>< :vertical resize -5<CR>
nnoremap <leader>+ :resize +5<CR>
nnoremap <leader>- :resize -5<CR>
" Tabs
nnoremap <leader>tn :tabnext<CR>
nnoremap <leader>tp :tabprevious<CR>
nnoremap <leader>tc :tabclose<CR>
nnoremap <leader>t :tabnew<CR>
" Splits
nnoremap <leader>s :split<CR>
nnoremap <leader>v :vsplit<CR>
" Paste mode toggle
function! SafePasteToggle()
if &paste
set nopaste | echo "paste mode: OFF"
else
set paste | echo "paste mode: ON"
endif
endfunction
nnoremap <leader>pt :call SafePasteToggle()<CR>
nnoremap <leader>pp :call SafePasteToggle()<CR>
nnoremap <leader>ps :echo "paste mode: " . (&paste ? "ON" : "OFF")<CR>
set statusline+=%{&paste?'[PASTE]':''}
" EasyAlign: ga= to align by character
xmap ga <Plug>(EasyAlign)
nmap ga <Plug>(EasyAlign)
"*****************************************************************************
" VSCode Neovim specific settings
" These mappings call VSCode commands via VSCodeNotify.
" [Cursor side] No additional extensions required unless noted below.
"*****************************************************************************
if exists('g:vscode')
" Pane navigation (replaces <C-w>hjkl)
" [Cursor] Built-in pane navigation - no extension needed
nnoremap <C-h> :call VSCodeNotify('workbench.action.navigateLeft')<CR>
nnoremap <C-j> :call VSCodeNotify('workbench.action.navigateDown')<CR>
nnoremap <C-k> :call VSCodeNotify('workbench.action.navigateUp')<CR>
nnoremap <C-l> :call VSCodeNotify('workbench.action.navigateRight')<CR>
" File search (replaces fzf)
" [Cursor] Built-in Quick Open - no extension needed
nnoremap <leader>ff :call VSCodeNotify('workbench.action.quickOpen')<CR>
nnoremap <leader>fg :call VSCodeNotify('workbench.action.findInFiles')<CR>
nnoremap <leader>f. :call VSCodeNotify('workbench.action.openRecent')<CR>
" Explorer (replaces NERDTree)
" [Cursor] Built-in Explorer - no extension needed
nnoremap <leader>nt :call VSCodeNotify('workbench.view.explorer')<CR>
" Command Palette (replaces which-key)
" [Cursor] Built-in - no extension needed
nnoremap <leader>p :call VSCodeNotify('workbench.action.showCommands')<CR>
" Git panel (replaces vim-fugitive)
" [Cursor] Install: GitLens (eamodio.gitlens) for enhanced git features
nnoremap <leader>gs :call VSCodeNotify('workbench.view.scm')<CR>
nnoremap <leader>gp :call VSCodeNotify('git.push')<CR>
nnoremap <leader>gl :call VSCodeNotify('git.pull')<CR>
" Copilot toggle (replaces copilot.vim)
" [Cursor] Install: GitHub Copilot (github.copilot)
nnoremap <leader>cs :call VSCodeNotify('github.copilot.toggleCopilot')<CR>
" Buffer / editor management
nnoremap <leader>bd :call VSCodeNotify('workbench.action.closeActiveEditor')<CR>
nnoremap <leader>wq :call VSCodeNotify('workbench.action.files.saveAndCloseActiveEditor')<CR>
" Comment (uses VSCode built-in; also works via vim-commentary above)
xmap gc <Plug>VSCodeCommentary
nmap gc <Plug>VSCodeCommentary
omap gc <Plug>VSCodeCommentary
nmap gcc <Plug>VSCodeCommentaryLine
"*****************************************************************************
" Vim / Neovim terminal specific settings
"*****************************************************************************
else
" Window navigation
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
nnoremap <leader>wq :wq<CR>
nnoremap <leader>bd :bd<CR>
" NERDTree
nnoremap <leader>nt :NERDTreeToggle<CR>
let g:NERDTreeChDirMode=2
let g:NERDTreeWinSize = 50
" fzf
nnoremap <leader>ff :Files<CR>
nnoremap <leader>f. :Files %:p:h<CR>
" vifm
nnoremap <leader>vf :Vifm<CR>
nnoremap <leader>vv :Vifm %:p:h<CR>
nnoremap <leader>v/ :VsplitVifm<CR>
nnoremap <leader>v\ :SplitVifm<CR>
nnoremap <leader>vt :TabVifm<CR>
nnoremap <leader>vc :EditVifm .<CR>
" EasyMotion
nnoremap <leader><leader> <Plug>(easymotion-prefix)
" Markdown
nnoremap <leader>mp :MarkdownPreviewToggle<CR>
nnoremap <leader>mt :TableModeEnable<CR>
" LaTeX
nnoremap <leader>ll :VimtexCompile<CR>
nnoremap <leader>lv :VimtexView<CR>
nnoremap <leader>le :VimtexErrors<CR>
" Writing / distraction-free
nnoremap <leader>goyo :Goyo<CR>
nnoremap <leader>li :Limelight!!<CR>
nnoremap <leader>sp :SoftPencil<CR>
nnoremap <leader>hp :HardPencil<CR>
"--- Airline ---
let g:airline#extensions#tabline#enabled = 1
let g:airline_powerline_fonts = 1
let g:airline#extensions#tabline#formatter = 'default'
let g:airline#extensions#tabline#show_buffers = 1
" --- which-key ---
nnoremap <silent> <leader> :<C-u>WhichKey ','<CR>
vnoremap <silent> <leader> :<C-u>WhichKeyVisual ','<CR>
let g:which_key_timeout = 300
let g:which_key_use_floating_win = 1
let g:which_key_map = {}
let g:which_key_map.f = { 'name': '+find',
\ 'f': [':Files', 'files (cwd)'],
\ '.': [':Files %:p:h', 'files (this dir)'] }
let g:which_key_map.n = { 'name': '+nerdtree',
\ 't': [':NERDTreeToggle', 'toggle'] }
let g:which_key_map.g = { 'name': '+go',
\ 'r': [':GoRun', 'run'],
\ 'b': [':GoBuild', 'build'],
\ 't': [':GoTest', 'test'],
\ 'c': [':GoCoverageToggle', 'coverage'],
\ 'f': [':GoFmt', 'fmt'],
\ 'i': [':GoImports', 'imports'],
\ 'd': [':GoDecls', 'decls'],
\ 'D': [':GoDeclsDir', 'decls (dir)'],
\ 'o': [':GoDoc', 'doc'],
\ 'v': [':GoVet', 'vet'],
\ 'l': [':GoLint', 'lint'],
\ 'k': [':GoKeyify', 'keyify'] }
let g:which_key_map.r = { 'name': '+rust',
\ 'r': [':!cargo run', 'run'],
\ 'b': [':!cargo build', 'build'],
\ 't': [':!cargo test', 'test'],
\ 'c': [':!cargo check', 'check'],
\ 'f': [':RustFmt', 'fmt'],
\ 'd': [':RacerGoToDefinition', 'goto def'],
\ 's': [':RacerShowDocumentation','doc'] }
let g:which_key_map.p = { 'name': '+paste',
\ 't': [':call SafePasteToggle()', 'toggle'],
\ 's': [':echo "paste:".(&paste?"ON":"OFF")', 'status'] }
autocmd VimEnter * call which_key#register(',', 'g:which_key_map')
" --- Copilot ---
let g:copilot_no_tab_map = v:true
let g:copilot_assume_mapped = v:true
augroup copilot_setup
autocmd!
autocmd VimEnter * call SetupCopilotKeys()
augroup END
function! SetupCopilotKeys()
if exists('g:loaded_copilot')
imap <silent><script><expr> <C-J> copilot#Accept("")
imap <C-K> <Plug>(copilot-dismiss)
imap <C-L> <Plug>(copilot-next)
imap <C-H> <Plug>(copilot-previous)
imap <C-Right> <Plug>(copilot-accept-word)
imap <C-Down> <Plug>(copilot-accept-line)
nnoremap <leader>cs :Copilot status<CR>
nnoremap <leader>ce :Copilot enable<CR>
nnoremap <leader>cd :Copilot disable<CR>
endif
endfunction
" --- Python (jedi) ---
let g:jedi#auto_initialization = 1
let g:jedi#completions_enabled = 1
let g:jedi#popup_on_dot = 1
let g:jedi#completions_command = "<C-Space>"
let g:jedi#goto_command = "<leader>d"
let g:jedi#documentation_command = "K"
let g:jedi#usages_command = "<leader>n"
let g:jedi#rename_command = "<leader>r"
let g:jedi#use_splits_not_buffers = "right"
let g:jedi#show_call_signatures = "2"
let g:jedi#case_insensitive_completion = 1
" --- Go ---
let g:go_fmt_command = "goimports"
let g:go_fmt_autosave = 1
let g:go_imports_autosave = 1
let g:go_mod_fmt_autosave = 1
let g:go_highlight_types = 1
let g:go_highlight_fields = 1
let g:go_highlight_functions = 1
let g:go_highlight_function_calls = 1
let g:go_highlight_extra_types = 1
let g:go_highlight_generate_tags = 1
let g:go_highlight_operators = 1
let g:go_highlight_build_constraints = 1
let g:go_auto_type_info = 1
let g:go_auto_sameids = 1
let g:go_metalinter_autosave = 1
let g:go_metalinter_autosave_enabled = ['vet', 'golint']
let g:go_list_type = "quickfix"
let g:go_addtags_transform = "snakecase"
let g:go_def_mode = 'guru'
let g:go_decls_includes = "func,type"
nnoremap <leader>gr :GoRun<CR>
nnoremap <leader>gb :GoBuild<CR>
nnoremap <leader>gt :GoTest<CR>
nnoremap <leader>gc :GoCoverageToggle<CR>
nnoremap <leader>gf :GoFmt<CR>
nnoremap <leader>gi :GoImports<CR>
nnoremap <leader>gd :GoDecls<CR>
nnoremap <leader>gD :GoDeclsDir<CR>
nnoremap <leader>go :GoDoc<CR>
nnoremap <leader>gv :GoVet<CR>
nnoremap <leader>gl :GoLint<CR>
nnoremap <leader>gk :GoKeyify<CR>
" --- Rust ---
let g:rustfmt_autosave = 1
let g:rustfmt_emit_files = 1
let g:rustfmt_fail_silently = 0
let g:rust_clip_command = 'xclip -selection clipboard'
nnoremap <leader>rr :!cargo run<CR>
nnoremap <leader>rb :!cargo build<CR>
nnoremap <leader>rt :!cargo test<CR>
nnoremap <leader>rc :!cargo check<CR>
nnoremap <leader>rf :RustFmt<CR>
nnoremap <leader>rd :RacerGoToDefinition<CR>
nnoremap <leader>rs :RacerShowDocumentation<CR>
" --- Julia ---
nnoremap <leader>jr :!julia %<CR>
nnoremap <leader>jf :JuliaFormatterFormat<CR>
" --- Clojure ---
nnoremap <leader>ce :Eval<CR>
vnoremap <leader>ce :Eval<CR>
nnoremap <leader>cf :Eval (load-file "%")<CR>
nnoremap <leader>cn :Eval (in-ns 'user)<CR>
nnoremap <leader>cr :Require<CR>
nnoremap <leader>cR :Require!<CR>
nnoremap <leader>ct :RunTests<CR>
nnoremap <leader>cF :Fmt<CR>
" --- Kotlin ---
nnoremap <leader>kr :!kotlinc % -include-runtime -d %:r.jar && java -jar %:r.jar<CR>
nnoremap <leader>kc :!kotlinc %<CR>
nnoremap <leader>kt :!gradle test<CR>
nnoremap <leader>kb :!gradle build<CR>
" --- Scala ---
nnoremap <leader>sr :!scala %<CR>
nnoremap <leader>sc :!scalac %<CR>
" --- ALE ---
let g:ale_enabled = 1
let g:ale_completion_enabled = 0
let g:ale_fix_on_save = 1
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'never'
let g:ale_lint_on_insert_leave = 0
let g:ale_linters = {
\ 'sh': ['shellcheck'],
\ 'python': ['flake8', 'pylint'],
\ 'go': ['gofmt', 'golint', 'govet'],
\ 'rust': ['rust-analyzer'],
\ 'ocaml': ['ocamllsp'],
\ 'julia': ['languageserver'],
\ 'javascript': ['eslint'],
\ 'typescript': ['eslint'],
\ 'vim': ['vint'],
\ 'clojure': [],
\ 'kotlin': ['kotlinc', 'ktlint'],
\ 'scala': [],
\ 'nim': ['nimcheck'],
\ }
let g:ale_fixers = {
\ '*': ['remove_trailing_lines', 'trim_whitespace'],
\ 'sh': ['shfmt'],
\ 'python': ['autopep8', 'black'],
\ 'go': ['gofmt', 'goimports'],
\ 'rust': ['rustfmt'],
\ 'ocaml': ['ocamlformat'],
\ 'javascript': ['prettier', 'eslint'],
\ 'typescript': ['prettier', 'eslint'],
\ 'json': ['prettier'],
\ 'markdown': ['prettier'],
\ 'clojure': ['cljfmt'],
\ 'kotlin': ['ktlint'],
\ 'nim': ['nimpretty'],
\ }
let g:ale_python_flake8_options = '--max-line-length=120 --ignore=E501,E302,E303,W391,W293'
let g:ale_python_pylint_options = '--max-line-length=120 --disable=C0301,C0303,C0304,C0305'
" --- Limelight / Goyo ---
let g:limelight_conceal_ctermfg = 240
let g:limelight_conceal_guifg = '#777777'
let g:limelight_conceal_code = 1
let g:limelight_default_coefficient = 0.7
let g:limelight_paragraph_span = 1
let g:limelight_bop = '^\s'
let g:limelight_eop = '\ze\n^\s'
let g:limelight_priority = -1
augroup goyo_limelight
autocmd!
autocmd User GoyoEnter Limelight
autocmd User GoyoLeave Limelight!
augroup END
" --- Markdown Preview ---
let g:mkdp_auto_start = 0
let g:mkdp_auto_close = 1
let g:mkdp_refresh_slow = 0
let g:mkdp_theme = 'dark'
let g:mkdp_preview_options = {
\ 'mkit': {}, 'katex': {}, 'uml': {}, 'maid': {},
\ 'disable_sync_scroll': 0, 'sync_scroll_type': 'middle',
\ 'hide_yaml_meta': 1, 'disable_filename': 0
\ }
" --- vimtex ---
let g:vimtex_view_method = 'zathura'
" --- vim-indent-guides ---
let g:indent_guides_enable_on_vim_startup = 1
" --- Table mode ---
let g:table_mode_corner_char = '+'
let g:table_mode_header_fillchar = '-'
endif
"*****************************************************************************
" Plugin settings: common (both Vim and VSCode)
"*****************************************************************************
" Markdown
let g:vim_markdown_folding_disabled = 1
" Clojure / S-expressions
let g:clojure_align_multiline_strings = 1
let g:clojure_maxlines = 100
let g:sexp_enable_insert_mode_mappings = 0
let g:sexp_filetypes = 'clojure,scheme,lisp,timl'
" Julia
let g:julia_syntax_highlight_deprecated = 0
let g:julia_indent_align_brackets = 1
let g:julia_indent_align_funcargs = 1
" Kotlin / Scala
let g:kotlin_auto_detect_file_type = 1
let g:scala_scaladoc_indent = 1
"*****************************************************************************
" Filetype settings
"*****************************************************************************
filetype plugin indent on
augroup go_filetype
autocmd!
autocmd BufRead,BufNewFile *.go setfiletype go
autocmd FileType go setlocal tabstop=4 shiftwidth=4 softtabstop=4 noexpandtab
autocmd FileType go setlocal listchars=tab:\ \ ,trail:·,extends:>,precedes:< | setlocal list
augroup END
augroup rust_filetype
autocmd!
autocmd BufRead,BufNewFile *.rs setfiletype rust
autocmd FileType rust setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=100
augroup END
augroup ocaml_filetype
autocmd!
autocmd BufRead,BufNewFile *.ml,*.mli setfiletype ocaml
autocmd FileType ocaml setlocal tabstop=2 shiftwidth=2 softtabstop=2 expandtab textwidth=80
autocmd FileType ocaml setlocal commentstring=(*\ %s\ *)
augroup END
augroup julia_settings
autocmd!
autocmd BufRead,BufNewFile *.jl setfiletype julia
autocmd FileType julia setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=92
autocmd FileType julia setlocal commentstring=#\ %s
augroup END
augroup clojure_settings
autocmd!
autocmd BufRead,BufNewFile *.clj,*.cljs,*.cljc setfiletype clojure
autocmd FileType clojure setlocal tabstop=2 shiftwidth=2 softtabstop=2 expandtab lisp
augroup END
augroup kotlin_settings
autocmd!
autocmd BufRead,BufNewFile *.kt setfiletype kotlin
autocmd FileType kotlin setlocal tabstop=4 shiftwidth=4 softtabstop=4 expandtab textwidth=120
augroup END
augroup scala_settings
autocmd!
autocmd BufRead,BufNewFile *.scala,*.sbt setfiletype scala
autocmd FileType scala setlocal tabstop=2 shiftwidth=2 softtabstop=2 expandtab textwidth=120
autocmd FileType scala setlocal commentstring=//\ %s
augroup END
augroup nim_filetype
autocmd!
autocmd BufRead,BufNewFile *.nim setfiletype nim
augroup END
augroup markdown_settings
autocmd!
autocmd FileType markdown setlocal tabstop=2 shiftwidth=2 softtabstop=2
if !exists('g:vscode')
autocmd FileType markdown call pencil#init({'wrap': 'soft'})
endif
augroup END
augroup pencil_settings
autocmd!
autocmd User PencilEnter setlocal wrap linebreak nolist
autocmd User PencilLeave setlocal nowrap nolinebreak list!
augroup END
" Do not create undo files for temporary / generated files
augroup undo_ignore
autocmd!
autocmd BufWritePre /tmp/*,*.log,*.csv,*.dat,*.npz setlocal noundofile
augroup END
" end of file
A two-part tuning baseline for Ubuntu. Part 1 brings a general-purpose server to Level 2. Part 2 overlays the trading-specific deltas to reach Level 3. Honest about what it does — and explicitly not an HFT guide.
################################################################################
# Linux tuning for public-internet trading systems
# A Level-2/3 foundation — explicitly not an HFT guide
#
# Copyright (c) 2026 Gratice LLC. All rights reserved.
#
# Author: Yutaka TOMII
# Company: Gratice LLC
# Target: Ubuntu 22.04 / 24.04 LTS
# Updated: April 18, 2026
#
# --- Scope -------------------------------------------------------------------
# This document IS:
# * A practical tuning baseline for trading systems that talk to exchanges
# over the public internet (crypto WebSocket, REST, standard TCP APIs).
# * Level 2 for general-purpose high-load servers (Part 1).
# * Level 3 at its most aggressive (Part 1 + Part 2): CPU isolation,
# manual IRQ pinning, slew-only time sync, per-socket busy-poll.
# * Honest about what it does and does not accomplish.
#
# This document is NOT:
# * An HFT tuning guide.
# * A kernel-bypass reference (DPDK, AF_XDP, OpenOnload, ef_vi, TCPDirect).
# * A co-location / exchange-direct tutorial (CME, NASDAQ, TSE, ITCH, OUCH, FIX).
# * A substitute for PREEMPT_RT, FPGA offload, or microsecond-class engineering.
# * Applicable to workloads where tick-to-trade under 10 us is the design goal.
################################################################################################################################################################
# The level scale
#
# L0 — Out-of-box defaults. NOFILE=1024, CUBIC, stock irqbalance.
# Fresh install; adequate for low-traffic services.
# L1 — Basic production. NOFILE ~64k, somaxconn raised, noatime mount.
# Most small-to-mid SaaS backends.
# L2 — Well-tuned high-load server. file-max=1M, 128 MiB TCP buffers, <-- Part 1
# BBR+fq, systemd limits raised, I/O scheduler per device, THP managed.
# L3 — Low-latency oriented. isolcpus + nohz_full + rcu_nocbs, <-- Part 1 + Part 2
# manual IRQ pinning, performance governor, per-socket SO_BUSY_POLL,
# slew-only time sync, hardware timestamping where available.
# L4 — Microsecond HFT. Kernel bypass (DPDK / AF_XDP / OpenOnload),
# user-space TCP, PREEMPT_RT, hugetlbfs, SMT off, exchange co-location.
# L5 — Nanosecond league. FPGA TCP/UDP offload, L1 switches, microwave WAN,
# tick-to-trade entirely in silicon.
#
# --- Next-stage hints (toward Level 4) ---------------------------------------
# Hardware ........... Solarflare / Xilinx (ef_vi, OpenOnload), ConnectX-6+
# Kernel bypass ...... DPDK (full user-space) or AF_XDP (lighter)
# User-space TCP ..... Seastar, mTCP, F-Stack, TCPDirect
# Real-time kernel ... Ubuntu Pro PREEMPT_RT
# Huge pages ......... hugetlbfs with pre-allocated pages (replacing THP)
# SMT off ............ nosmt at boot + NUMA-aware allocator
# Physical placement . exchange co-location, same rack when possible
# Measurement ........ cyclictest, perf sched, HW timestamp diffs, TSC cal
#
# Every Level-4 change is a hypothesis to be measured, not a best practice
# to be applied. Best practices are not a substitute for measurement.
################################################################################# /etc/sysctl.d/99-ubuntu-general.conf
# Apply: sudo sysctl --system
# === File descriptors ===
# System-wide open file limit. Prevents EMFILE/ENFILE under high concurrency.
fs.file-max = 1048576
# === mmap / VM ===
# Per-process mmap region count. Required by QuestDB, Elasticsearch, etc.
vm.max_map_count = 1048576
# Minimize swapping without disabling it. 10 is the general-server sweet spot.
# Setting 0 makes the OOM killer fire sooner than expected.
vm.swappiness = 10
# === Dirty writeback ===
vm.dirty_background_ratio = 5
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
# === Network backlog ===
# accept() queue depth for listen sockets; absorbs SYN bursts.
net.core.somaxconn = 65535
# NIC -> kernel packet queue; absorbs traffic bursts.
net.core.netdev_max_backlog = 262144
# NAPI polling budget. Default 300 drops packets under heavy bursts.
net.core.netdev_budget = 600
net.core.netdev_budget_usecs = 8000
# === TCP buffers ===
# Raise ceiling for high bandwidth-delay products (128 MiB).
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# === TCP tuning ===
net.ipv4.tcp_fin_timeout = 15
# TIME-WAIT reuse is CLIENT-side only; does not affect server sockets.
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_mtu_probing = 1
# === Ports ===
net.ipv4.ip_local_port_range = 10240 65535
# === inotify ===
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 524288
# === Security baseline ===
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
kernel.kptr_restrict = 1
kernel.dmesg_restrict = 1
# Intentionally NOT included here (Part 2 territory):
# vm.overcommit_memory = 1 (Redis-specific; early OOM elsewhere)
# kernel.numa_balancing = 0 (only sensible when pinning)
# kernel.shmmax / shmall (workload-specific)
# net.core.busy_poll (prefer per-socket SO_BUSY_POLL)# --- /etc/sysctl.d/10-bbr.conf -----------------------------------------------
# fq qdisc enables pacing, which BBR requires.
# In a data center (RTT < 1ms) BBR and CUBIC are near-tied; the benefit
# shows on WAN paths, high-RTT links, and lossy networks.
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# --- /etc/systemd/system.conf ------------------------------------------------
# systemd limits are hit BEFORE sysctl limits.
# These apply to every systemd-managed service.
[Manager]
DefaultLimitNOFILE=1048576
DefaultLimitNPROC=500000
DefaultTasksMax=infinity
# Apply: sudo systemctl daemon-reexec
# Existing services pick up the new defaults only after restart.
# --- /etc/security/limits.d/99-highload.conf ---------------------------------
# PAM-based limits apply to LOGIN SESSIONS ONLY.
# systemd services ignore this file — see system.conf above.
# Both mechanisms are required for full coverage.
* soft nofile 1048576
* hard nofile 1048576
* soft nproc unlimited
* hard nproc unlimited
* soft memlock unlimited
* hard memlock unlimited
# Ubuntu already loads pam_limits.so in /etc/pam.d/common-session.
# Confirm with:
# grep pam_limits /etc/pam.d/common-session*# --- /etc/udev/rules.d/60-ioschedulers.rules ---------------------------------
# NVMe: none (no block-layer reordering; measurably faster).
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/scheduler}="none"
# SATA/SAS SSD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# HDD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
# Reload:
# sudo udevadm control --reload
# sudo udevadm trigger --type=devices --action=change
# --- /etc/fstab (data volumes) -----------------------------------------------
# noatime kills per-access timestamp writes; visibly reduces write I/O.
# Example:
# UUID=xxxx-xxxx /var/lib/data ext4 defaults,noatime,nodiratime 0 2
# --- /etc/systemd/system/thp.service (general-purpose: madvise) -------------
# DB-dedicated hosts use 'never' — see Part 2.
[Unit]
Description=Set Transparent Huge Pages to madvise
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=basic.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo madvise > /sys/kernel/mm/transparent_hugepage/defrag'
RemainAfterExit=yes
[Install]
WantedBy=basic.target
# Enable:
# sudo systemctl enable --now thp.service
# --- IRQ balancing (general-purpose: ENABLED) --------------------------------
# sudo apt-get install -y irqbalance
# sudo systemctl enable --now irqbalance
# Trading workloads disable this and pin IRQs manually — see Part 2.# Observe for 24-72 hours after applying Part 1.
# No metric should show abnormal growth.
# File descriptor usage vs. limit
cat /proc/sys/fs/file-nr
# TCP state summary
ss -s
# Disk I/O wait
iostat -x 1 5
# Dirty / writeback memory pressure
grep -E 'Dirty|Writeback' /proc/meminfo
# Interrupt distribution across cores
cat /proc/interrupts | awk 'NR==1 || /eth|nvme/'
# Confirm sysctl application
sudo sysctl --system 2>&1 | grep -iE 'applying|error'
# BBR active?
sysctl net.ipv4.tcp_congestion_control
lsmod | grep bbr
tc qdisc show dev eth0
# I/O scheduler per device
cat /sys/block/nvme0n1/queue/scheduler# /etc/sysctl.d/99-trading.conf
# Layered ON TOP of the general-purpose profile.
# Same key in multiple files: last-loaded wins. Keep number <= 99.
# Avoid fork-time COW failure for Redis / QuestDB / memory-locked workloads.
# Side effect: allocations that would normally be refused may succeed
# and trigger OOM later. Use ONLY on dedicated DB / trading hosts.
vm.overcommit_memory = 1
vm.overcommit_ratio = 90
# Minimize swap interference. Complements memlock for strict in-memory behavior.
vm.swappiness = 1
# Disable NUMA balancing.
# REQUIRES explicit pinning via taskset / numactl / systemd CPUAffinity.
# Without pinning this setting is a net negative.
kernel.numa_balancing = 0
# Large shared memory segments (PostgreSQL, some QuestDB modes).
# Values assume a 64 GiB host; scale to physical RAM.
kernel.shmmni = 8192
kernel.shmmax = 68719476736
kernel.shmall = 16777216
# SysV semaphores (PostgreSQL requirement)
kernel.sem = 250 64000 100 4096
# conntrack scaling — ONLY when the host also acts as NAT / stateful firewall.
# A standalone trading server does not need this block.
# net.netfilter.nf_conntrack_max = 1048576
# net.netfilter.nf_conntrack_tcp_timeout_established = 600# --- /etc/default/grub -------------------------------------------------------
# 8C/16T example: housekeeping=0-7, trading-isolated=8-15.
#
# Verify SMT sibling layout FIRST (AMD and Intel differ):
# lscpu -e
# Rows with the same CORE value are SMT siblings.
#
# Ubuntu/Debian variable. RHEL-family uses GRUB_CMDLINE_LINUX.
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash \
isolcpus=managed_irq,domain,8-15 \
nohz_full=8-15 \
rcu_nocbs=8-15 \
rcu_nocb_poll \
irqaffinity=0-7 \
processor.max_cstate=1 \
intel_idle.max_cstate=0 \
idle=poll \
mitigations=off"
# isolcpus .................... remove CPUs from the normal scheduler
# nohz_full ................... stop 1000 Hz tick on single-task CPUs
# rcu_nocbs + rcu_nocb_poll ... offload RCU callbacks from isolated CPUs
# irqaffinity ................. default IRQ affinity mask at boot
# processor.max_cstate=1 ...... forbid deep idle states (wake latency)
# idle=poll ................... spin instead of sleeping; latency=0, power up
# mitigations=off ............. disable Spectre/Meltdown mitigations
# ONLY on trusted, dedicated hosts
# Apply:
# sudo update-grub
# sudo reboot
# Verify:
# cat /proc/cmdline
# cat /sys/devices/system/cpu/isolated
# cat /sys/devices/system/cpu/nohz_full# --- Disable irqbalance; pin NIC IRQs manually -------------------------------
sudo systemctl disable --now irqbalance
# Find NIC IRQ numbers
grep -E 'eth0|ens' /proc/interrupts
# Pin every eth0 IRQ to housekeeping cores 0-7
for irq in $(awk '/eth0/ {gsub(":",""); print $1}' /proc/interrupts); do
echo "0-7" | sudo tee /proc/irq/$irq/smp_affinity_list
done
# Multi-queue RSS (raise to hardware maximum)
ethtool -l eth0
sudo ethtool -L eth0 combined 8
# Ring buffers (drop prevention under bursts)
ethtool -g eth0
sudo ethtool -G eth0 rx 4096 tx 4096
# --- /etc/systemd/system/trading-engine.service.d/cpu.conf -------------------
# Pin the trading process to isolated cores 12-15.
# isolcpus reserves cores; this places the process onto them.
[Service]
CPUAffinity=12 13 14 15
Nice=-20
IOSchedulingClass=realtime
IOSchedulingPriority=0
# Apply:
# sudo systemctl daemon-reload
# sudo systemctl restart trading-engine
# Verify:
# taskset -cp $(pgrep trading-engine)
# Multi-socket hosts: pin memory to the same NUMA node
# numactl --cpunodebind=0 --membind=0 ./trading-engine# --- THP disabled entirely (dedicated DB / trading hosts) -------------------
# Replace thp.service ExecStart lines with:
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
# echo never > /sys/kernel/mm/transparent_hugepage/defrag
# Matches the official Redis and MongoDB recommendations.
# sudo systemctl daemon-reload
# sudo systemctl restart thp.service
# cat /sys/kernel/mm/transparent_hugepage/enabled # expect [never]
# --- CPU governor: performance (eliminate clock-ramp latency) ---------------
sudo apt-get install -y cpufrequtils
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils
sudo systemctl restart cpufrequtils
cpupower frequency-info
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor | sort -u
# --- /etc/chrony/chrony.conf (slew-only, never step) ------------------------
# Monotonic timestamps matter more than exact offset.
# A clock step breaks the ordering of trade logs.
# AWS EC2: link-local NTP, one hop away
server 169.254.169.123 prefer iburst minpoll 4 maxpoll 4
# Regional low-latency NTP
pool ntp.nict.jp iburst
# Never step the clock. makestep -1 disables stepping entirely.
# Even a large boot-time offset is corrected by slewing.
makestep 1.0 -1
lock_all
driftfile /var/lib/chrony/chrony.drift
rtcsync
logdir /var/log/chrony
# Verify: chronyc sources -v ; chronyc tracking
# Offset within +/- 100 us is healthy.
# Hardware timestamping (PHC-capable NIC):
# ethtool -T eth0
# hardware-receive / hardware-transmit / hardware-raw-clock must be YES.// --- Go: per-socket busy-poll + Nagle off ---------------------------------
// Per-socket SO_BUSY_POLL is preferred over the global sysctl.
conn.Control(func(fd uintptr) {
// syscall.SO_BUSY_POLL = 46
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, 46, 50) // 50 us busy poll
})
tcpConn.SetNoDelay(true)
// Pin this goroutine to its current OS thread.
// Combined with external taskset, the goroutine becomes effectively pinned.
runtime.LockOSThread()
// --- QuestDB: ILP over HTTP (port 9000) ------------------------------------
// UDP ILP was deprecated in QuestDB 6.5.2; do not use it.
import qdb "github.com/questdb/go-questdb-client/v3"
sender, _ := qdb.LineSenderFromConf(ctx, "http::addr=localhost:9000;")
defer sender.Close(ctx)
sender.Table("trades").
Symbol("symbol", "BTCUSDT").
Float64Column("price", 95000.5).
StringColumn("side", "buy").
At(ctx, time.Now())
sender.Flush(ctx)
// --- Python: per-socket busy-poll + kernel timestamps ----------------------
// import socket, struct, os
//
// sock.setsockopt(socket.SOL_SOCKET, 46, 50) # SO_BUSY_POLL
// sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
// sock.setsockopt(socket.SOL_SOCKET, socket.SO_TIMESTAMPNS, 1) # Python 3.9+
//
// # Unpack timespec. On 64-bit Linux: two int64 fields.
// # Using "qq" makes the width explicit; avoid "LL" (C long is platform-sized).
// sec, nsec = struct.unpack("qq", cmsg_data)
//
// # Pin this process to CPUs 12-14 (isolated set).
// os.sched_setaffinity(0, {12, 13, 14})
// --- QuestDB from Python ---------------------------------------------------
// from questdb.ingress import Sender, TimestampNanos
// with Sender.from_conf("http::addr=localhost:9000;") as sender:
// sender.row(
// "trades",
// symbols={"symbol": "BTCUSDT", "side": "buy"},
// columns={"price": 95000.5, "amount": 0.01},
// at=TimestampNanos.now(),
// )
// sender.flush()
// --- Runtime tuning (Go) ---------------------------------------------------
// export GOMAXPROCS=4 # match the isolated core count
// export GOGC=200 # lower GC frequency (memory-permitting)
// taskset -c 12-15 ./trading-engine# --- Part 2 verification -----------------------------------------------------
# Isolated cores should show near-zero %usr for anything other than the app.
mpstat -P ALL 1 5
# Interrupt counts on isolated cores should NOT grow.
cat /proc/interrupts | awk '/eth0/ {print}'
# Context-switch frequency on the trading process — should be minimal.
pidstat -w -p $(pgrep trading-engine) 1
# Time-sync jitter
chronyc tracking | grep -E 'Last offset|RMS offset|System time'
# CPU frequency pinned at the performance ceiling
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq | sort -u
# Latency distribution — the final arbiter
sudo apt-get install -y rt-tests
sudo cyclictest -p 99 -t1 -a 12 -n -m -D 60
# Max latency under 50 us indicates a healthy Level-3 setup.
# --- Application order -------------------------------------------------------
# 1. Apply Part 1 in full. Most requires no reboot. Observe 24-72h.
# 2. Add /etc/sysctl.d/99-trading.conf alone. Observe.
# 3. THP = never (on dedicated DB hosts). Observe.
# 4. Governor = performance. Watch power.
# 5. Stop irqbalance + pin IRQs. Watch for drops.
# 6. GRUB parameters. REQUIRES REBOOT. Back up current cmdline first.
# 7. CPUAffinity + SO_BUSY_POLL last.
# At each step, cyclictest Max should decrease. If not, investigate.
# --- Rollback (each change is isolated to a single file) --------------------
# sysctl: sudo rm /etc/sysctl.d/99-*.conf && sudo sysctl --system
# systemd: revert /etc/systemd/system.conf ; sudo systemctl daemon-reexec
# THP: sudo systemctl disable --now thp.service
# GRUB: restore /etc/default/grub cmdline ; sudo update-grub ; reboot
# IRQs: sudo systemctl enable --now irqbalance
#
# This document gets a public-internet trading system to a well-engineered
# state. It does NOT turn it into an HFT system. Preserve that distinction.