{
    "archive_path": "archive/1765072779.899126",
    "base_url": "andrej.sh/blog/maintaining-open-source-project",
    "basename": "",
    "bookmarked_date": "2025-12-07 01:59",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/andrej.sh/blog/maintaining-open-source-project",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=andrej.sh",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": null
    },
    "domain": "andrej.sh",
    "downloaded_at": "2025-12-07T01:59:43.460381+00:00",
    "downloaded_datestr": "2025-12-07 01:59",
    "extension": "",
    "hash": "ZSPM1NMD51818ZMY9RXG",
    "history": {
        "archive_org": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://web.archive.org/save/https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-07T02:01:21.875566+00:00",
                "index_texts": null,
                "output": "TimeoutExpired: Command '['/usr/bin/curl', '--silent', '--location', '--compressed', '--proxy', 'socks5://tor-socks-proxy:9150', '--head', '--max-time', '60', '--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)', 'https://web.archive.org/save/https://andrej.sh/blog/maintaining-open-source-project/']' timed out after 60 seconds",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T02:00:21.806766+00:00",
                "status": "failed"
            }
        ],
        "dom": [
            {
                "cmd": [
                    "/usr/bin/chromium-browser",
                    "--proxy-server=socks5://tor-socks-proxy:9150",
                    "--disable-features=DarkMode",
                    "--run-all-compositor-stages-before-draw",
                    "--hide-scrollbars",
                    "--autoplay-policy=no-user-gesture-required",
                    "--no-first-run",
                    "--use-fake-ui-for-media-stream",
                    "--use-fake-device-for-media-stream",
                    "--simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT'",
                    "--headless=new",
                    "--no-sandbox",
                    "--no-zygote",
                    "--disable-dev-shm-usage",
                    "--disable-software-rasterizer",
                    "--disable-sync",
                    "--window-size=1440,2000",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "--user-data-dir=/data/personas/Default/chrome_profile",
                    "--profile-directory=Default",
                    "--dump-dom",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "131.0.6778",
                "end_ts": "2025-12-07T01:59:52.286456+00:00",
                "index_texts": null,
                "output": "output.html",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:46.653906+00:00",
                "status": "succeeded"
            }
        ],
        "favicon": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.google.com/s2/favicons?domain=andrej.sh"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-07T01:59:46.380804+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:43.481504+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-07T01:59:46.564256+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:46.403640+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [
            {
                "cmd": [
                    "(internal) archivebox.extractors.htmltotext",
                    "./{singlefile,dom}.html"
                ],
                "cmd_version": "0.8.5rc51",
                "end_ts": "2025-12-07T02:00:07.034476+00:00",
                "index_texts": [
                    "What They Don't Tell You About Maintaining an Open Source Project ~ andrej acevski (andrej acevski) (https://andrej.sh/rss) (/static/favicon.ico) (/static/favicon-16x16.png) (/static/favicon-32x32.png) (/static/favicon-96x96.png) (/static/favicon.svg) (/static/apple-touch-icon.png) (/static/site.webmanifest) (/static/fonts/JetBrainsMono-Regular.woff2) (/static/css/main.css) (/static/css/site.css) (/static/css/main.css)  (/) home (/blog) blog (/books) books (/rss.xml) rss  \u2318 K    (/blog) \u2190 back to blog  What They Don't Tell You About Maintaining an Open Source Project  2025-11-25 \u00b7 9 min read  the beginning building (https://kaneo.app) kaneo was fun. a clean, minimal kanban board. self-hosted. open source. no tracking, no subscriptions, no bullshit. i shipped v1, posted it on reddit, got some stars on github. people actually used it. that feeling when someone tells you they're using something you built? incredible. then i learned that shipping is just the beginning.  the documentation challenge i spent hours writing documentation. setup guides, configuration examples, troubleshooting sections. tried to make it clear and comprehensive. but here's the thing: people come from different backgrounds. what's obvious to me after building the thing isn't obvious to someone installing it for the first time. someone opens an issue: \"how do i install this?\" my first reaction was frustration. it's in the readme! but then i realized - maybe the readme assumes too much. maybe they're new to docker. maybe they're coming from windows and linux is foreign. so i improved the docs: added more examples created a troubleshooting guide made a video walkthrough added a \"common issues\" section  it's a constant process. documentation is never \"done.\" support is product development maintaining kaneo means helping people debug their setups. and honestly? it's taught me more than i expected. people run kaneo on setups i never imagined: behind corporate proxies on raspberry pi clusters in kubernetes with custom networking on nas devices with limited resources  each support request reveals an assumption i made. each \"it doesn't work\" issue (even the ones without details) points to a failure mode i didn't consider. the challenge is balancing time. i want to help everyone. but i also have a day job. and new features to build. and bugs to fix. i'm still learning how to set boundaries while being helpful. feature requests are humbling people want kaneo to do more. and that's amazing! it means they're actually using it. they care enough to imagine what it could be. but every feature request is a decision:  does this fit the vision? can i maintain this long-term? will this complicate the codebase? what else won't get built if i build this?  saying no is hard. especially when the request is thoughtful and well-reasoned. especially when someone offers to help implement it. i've learned to be transparent: \"i love this idea, but it's outside kaneo's scope. here's why...\" most people understand. some don't. that's okay. migrations are terrifying the database schema needed a refactor. the current design was limiting. the new design would enable features people wanted. but 200+ people were using kaneo in production. their actual work data. their team's workflows.  if i broke the migration, they'd lose trust. maybe lose data. definitely lose sleep. so i: wrote the migration script tested it on every version going back to v1 wrote detailed upgrade notes tested edge cases tested the edge cases of edge cases added validation checks added dry-run mode  released it. held my breath. most migrations went smoothly. a few didn't. not because people didn't read the notes - but because they had setups i couldn't have predicted: modified databases custom patches environments i'd never seen  we debugged together. they were patient. i was grateful. every migration taught me something new about defensive programming. contributors are a gift when someone submits a pr, it's incredible. someone cared enough to spend their time improving kaneo.  but integrating contributions is harder than i expected: different coding styles different assumptions about architecture different ideas about what kaneo should be  sometimes a pr is perfect. sometimes it needs work. sometimes it's solving a problem in a way that'll create more problems later. i've learned to: appreciate the effort, always explain my reasoning when requesting changes be okay with saying \"this doesn't fit, but i appreciate you\" sometimes just fix it myself if it's close  the contributors who stick around? they're amazing. they've made kaneo better than i could alone. the diversity of environments self-hosting means people run kaneo everywhere:  # docker on their laptops   docker compose up -d     # kubernetes clusters at work   kubectl apply -f kaneo.yaml     # raspberry pi in their home lab   # (with 1GB of RAM and dreams)     # bare metal on old servers   # (that have been running since 2015)     # nas devices with arm processors   # (that i've never even heard of)    copy  each environment teaches me something. each \"it doesn't work on my setup\" issue reveals an assumption i made about how systems work. i can't test every environment. but i can make kaneo more resilient: better error messages clearer logs more graceful failures  the people running kaneo on weird setups? they're often the most helpful. they understand their environment. they provide detailed logs. they test fixes. we figure it out together. keeping documentation alive documentation is never finished. every feature needs docs. every bug fix might need docs. every question reveals a gap in docs. i've learned to: update docs in the same pr as code changes treat \"docs are wrong\" issues as high priority appreciate when people submit doc fixes accept that docs will never be perfect  the goal isn't perfect documentation. it's documentation that helps most people most of the time. and when it doesn't? that's feedback. that's how it gets better. the comparison question \"why not just use trello/notion/linear?\"  it's a fair question. those tools are great. they have teams of engineers, designers, product managers. they're polished. they're fast. they're feature-rich. kaneo is different: them kaneo   cloud-hosted self-hosted (your data, your server)  closed source open source (you can read every line)  feature-rich minimal (does one thing well)  subscription free (as in freedom and beer)    it's not better. it's different. for some people, that difference matters. and honestly? building kaneo taught me more than using those tools ever could. the emotional reality maintaining open source is a rollercoaster: someone stars your repo \u2192 feels good someone opens a detailed bug report with logs and reproduction steps \u2192 feels great someone says \"kaneo saved our team\" \u2192 feels incredible someone opens an issue titled \"this is trash\" \u2192 hurts more than it should you spend a weekend implementing a requested feature \u2192 crickets you fix a small bug \u2192 three people thank you you realize you haven't worked on your own roadmap in months \u2192 exhausting someone submits a thoughtful pr \u2192 you're not alone the highs are high. the lows are low. but the people who use kaneo, who contribute, who care? they make it worth it. what i learned 1. scope is everything kaneo does one thing: kanban boards. not project management. not time tracking. not team chat. every feature you add is a feature you maintain forever. being clear about scope isn't limiting - it's liberating. it lets you focus. it lets you say no without guilt. 2. automate everything you can # .github/workflows/ci.yml     name :  CI     on :  [ push, pull_request]     jobs :     test :     - run :  npm test     security :     - run :  npm audit     release :     - run :  semantic-release     copy  automation isn't lazy. it's sustainable: automated tests catch bugs before users do automated releases mean less manual work automated security scans give peace of mind automated dependency updates keep things current  it frees you to focus on what matters. 3. good issue templates help everyone github issue templates help people provide: system info error logs steps to reproduce  it's not about gatekeeping. it's about making debugging possible. most people want to help you help them. templates make that easier. 4. saying no is an act of respect you can't build everything. saying yes to everything means doing nothing well. being honest about what you can and can't do respects everyone's time. including yours. 5. users are collaborators the people using kaneo aren't just users. they're: beta testers finding bugs documentation editors spotting gaps feature designers sharing ideas community builders helping each other  they're not demanding. they're engaged. that's a gift.  when someone opens an issue, they're investing time in making kaneo better. even if the issue is unclear, the intent is good. patience and kindness aren't just nice. they're necessary. the honest truth maintaining an open source, self-hosted project is: more work than building it different fun than building it more rewarding than you'd expect harder than you'd expect worth it  you learn: technical skills (migrations, security, scalability) people skills (communication, patience, boundaries) product skills (prioritization, scope, vision) how to appreciate every contribution how to build something people actually want  my setup (the real one) \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  kaneo infrastructure               \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502  github                             \u2502\n\u2502  \u251c\u2500 code + issues                   \u2502\n\u2502  \u251c\u2500 actions (ci/cd)                 \u2502\n\u2502  \u2514\u2500 container registry              \u2502\n\u2502                                     \u2502\n\u2502  hetzner ($7/month)                 \u2502\n\u2502  \u2514\u2500 cloud instance                  \u2502\n\u2502                                     \u2502\n\u2502  cloudflare (free)                  \u2502\n\u2502  \u2514\u2500 dns + ddos protection           \u2502\n\u2502                                     \u2502\n\u2502  plausible                          \u2502\n\u2502  \u2514\u2500 privacy-friendly analytics      \u2502\n\u2502                                     \u2502\n\u2502  coffee (priceless)                 \u2502\n\u2502  \u2514\u2500 way too much                    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  copy  what i'd tell past me 1. invest in documentation early - good docs reduce support burden and help people succeed. it's time well spent. 2. automate from day one - tests, releases, security scans. automation scales. you don't. 3. be clear about scope - say what your project is AND what it isn't. it helps everyone. 4. migrations are worth the extra effort - test thoroughly. add rollbacks. write clear upgrade notes. your users trust you with their data. 5. it's okay to be slow - you're not a company. you're a person. set expectations. take breaks. protect your energy. 6. celebrate your users - every person using kaneo is amazing. they chose to trust something you built. that's incredible. 7. the community is the product - the code matters, but the people matter more. invest in both. the conclusion would i do it again? absolutely.  kaneo exists because i wanted a simple kanban board that i controlled. but it became something more: a community of people who value privacy, simplicity, and owning their tools. the maintenance is real work. the migrations are stressful. the support takes time. but people are using kaneo to: run their businesses manage their side projects organize their teams learn about self-hosting  they send thank you messages. they submit thoughtful bug reports. they contribute code. they help each other in discussions. that's not just cool. that's why i do this. kaneo is open source and free forever. check it out: (https://github.com/usekaneo/kaneo) github.com/usekaneo/kaneo   if you're using it, thank you. if you're contributing, you're amazing. if you're thinking about it, the docs are pretty good.  and if you find a bug? i'll fix it. probably at 11pm. but i'll fix it.     (https://github.com/aacevski) github  \u00b7 (https://x.com/andrejsshell) x       (search...) (/) home \u2192  (/blog) blog \u2192  (/books) books \u2192  (/rss) rss \u2192        "
                ],
                "output": "htmltotext.txt",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T02:00:06.758001+00:00",
                "status": "succeeded"
            }
        ],
        "media": [
            {
                "cmd": [
                    "/usr/local/bin/yt-dlp",
                    "--restrict-filenames",
                    "--trim-filenames",
                    "128",
                    "--write-description",
                    "--write-info-json",
                    "--write-annotations",
                    "--write-thumbnail",
                    "--no-call-home",
                    "--write-sub",
                    "--write-auto-subs",
                    "--convert-subs=srt",
                    "--yes-playlist",
                    "--continue",
                    "--no-abort-on-error",
                    "--ignore-errors",
                    "--geo-bypass",
                    "--add-metadata",
                    "--format=(bv*+ba/b)[filesize<=750m][filesize_approx<=?750m]/(bv*+ba/b)",
                    "--skip-download",
                    "--cache-dir=/data/yt-dlp-cache/",
                    "--cookies=/data/yt-dlp-cache/cookies.txt",
                    "--proxy=socks5://tor-socks-proxy:9150",
                    "--no-playlist",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "2024.10.7",
                "end_ts": "2025-12-07T02:00:21.763487+00:00",
                "index_texts": [],
                "output": "media/",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T02:00:15.154716+00:00",
                "status": "succeeded"
            }
        ],
        "mercury": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/postlight-parser",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "2.2.3",
                "end_ts": "2025-12-07T02:00:06.382566+00:00",
                "index_texts": null,
                "output": "mercury/",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:56.888151+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/readability-extractor",
                    "/tmp/tmpnvdm5hgy",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2025-12-07T01:59:56.741579+00:00",
                "index_texts": [
                    "the beginning\nbuilding kaneo was fun. a clean, minimal kanban board. self-hosted. open source. no tracking, no subscriptions, no bullshit.\ni shipped v1, posted it on reddit, got some stars on github. people actually used it. that feeling when someone tells you they're using something you built? incredible.\nthen i learned that shipping is just the beginning.\nthe documentation challenge\ni spent hours writing documentation. setup guides, configuration examples, troubleshooting sections. tried to make it clear and comprehensive.\nbut here's the thing: people come from different backgrounds. what's obvious to me after building the thing isn't obvious to someone installing it for the first time.\nsomeone opens an issue: \"how do i install this?\"\nmy first reaction was frustration. it's in the readme! but then i realized - maybe the readme assumes too much. maybe they're new to docker. maybe they're coming from windows and linux is foreign.\nso i improved the docs:\n\nadded more examples\ncreated a troubleshooting guide\nmade a video walkthrough\nadded a \"common issues\" section\n\nit's a constant process. documentation is never \"done.\"\nsupport is product development\nmaintaining kaneo means helping people debug their setups. and honestly? it's taught me more than i expected.\npeople run kaneo on setups i never imagined:\n\nbehind corporate proxies\non raspberry pi clusters\nin kubernetes with custom networking\non nas devices with limited resources\n\neach support request reveals an assumption i made. each \"it doesn't work\" issue (even the ones without details) points to a failure mode i didn't consider.\nthe challenge is balancing time. i want to help everyone. but i also have a day job. and new features to build. and bugs to fix.\ni'm still learning how to set boundaries while being helpful.\nfeature requests are humbling\npeople want kaneo to do more. and that's amazing! it means they're actually using it. they care enough to imagine what it could be.\nbut every feature request is a decision:\n\ndoes this fit the vision?\ncan i maintain this long-term?\nwill this complicate the codebase?\nwhat else won't get built if i build this?\n\nsaying no is hard. especially when the request is thoughtful and well-reasoned. especially when someone offers to help implement it.\ni've learned to be transparent: \"i love this idea, but it's outside kaneo's scope. here's why...\"\nmost people understand. some don't. that's okay.\nmigrations are terrifying\nthe database schema needed a refactor. the current design was limiting. the new design would enable features people wanted.\nbut 200+ people were using kaneo in production. their actual work data. their team's workflows.\nif i broke the migration, they'd lose trust. maybe lose data. definitely lose sleep.\nso i:\n\nwrote the migration script\ntested it on every version going back to v1\nwrote detailed upgrade notes\ntested edge cases\ntested the edge cases of edge cases\nadded validation checks\nadded dry-run mode\n\nreleased it. held my breath.\nmost migrations went smoothly. a few didn't. not because people didn't read the notes - but because they had setups i couldn't have predicted:\n\nmodified databases\ncustom patches\nenvironments i'd never seen\n\nwe debugged together. they were patient. i was grateful.\nevery migration taught me something new about defensive programming.\ncontributors are a gift\nwhen someone submits a pr, it's incredible. someone cared enough to spend their time improving kaneo.\nbut integrating contributions is harder than i expected:\n\ndifferent coding styles\ndifferent assumptions about architecture\ndifferent ideas about what kaneo should be\n\nsometimes a pr is perfect. sometimes it needs work. sometimes it's solving a problem in a way that'll create more problems later.\ni've learned to:\n\nappreciate the effort, always\nexplain my reasoning when requesting changes\nbe okay with saying \"this doesn't fit, but i appreciate you\"\nsometimes just fix it myself if it's close\n\nthe contributors who stick around? they're amazing. they've made kaneo better than i could alone.\nthe diversity of environments\nself-hosting means people run kaneo everywhere:\n# docker on their laptops\ndocker compose up -d\n\n# kubernetes clusters at work\nkubectl apply -f kaneo.yaml\n\n# raspberry pi in their home lab\n# (with 1GB of RAM and dreams)\n\n# bare metal on old servers\n# (that have been running since 2015)\n\n# nas devices with arm processors\n# (that i've never even heard of)\neach environment teaches me something. each \"it doesn't work on my setup\" issue reveals an assumption i made about how systems work.\ni can't test every environment. but i can make kaneo more resilient:\n\nbetter error messages\nclearer logs\nmore graceful failures\n\nthe people running kaneo on weird setups? they're often the most helpful. they understand their environment. they provide detailed logs. they test fixes.\nwe figure it out together.\nkeeping documentation alive\ndocumentation is never finished. every feature needs docs. every bug fix might need docs. every question reveals a gap in docs.\ni've learned to:\n\nupdate docs in the same pr as code changes\ntreat \"docs are wrong\" issues as high priority\nappreciate when people submit doc fixes\naccept that docs will never be perfect\n\nthe goal isn't perfect documentation. it's documentation that helps most people most of the time.\nand when it doesn't? that's feedback. that's how it gets better.\nthe comparison question\n\n\"why not just use trello/notion/linear?\"\n\nit's a fair question. those tools are great. they have teams of engineers, designers, product managers. they're polished. they're fast. they're feature-rich.\nkaneo is different:\n\n\n\nthem\nkaneo\n\n\n\n\ncloud-hosted\nself-hosted (your data, your server)\n\n\nclosed source\nopen source (you can read every line)\n\n\nfeature-rich\nminimal (does one thing well)\n\n\nsubscription\nfree (as in freedom and beer)\n\n\n\nit's not better. it's different. for some people, that difference matters.\nand honestly? building kaneo taught me more than using those tools ever could.\nthe emotional reality\nmaintaining open source is a rollercoaster:\nsomeone stars your repo \u2192 feels good\nsomeone opens a detailed bug report with logs and reproduction steps \u2192 feels great\nsomeone says \"kaneo saved our team\" \u2192 feels incredible\nsomeone opens an issue titled \"this is trash\" \u2192 hurts more than it should\nyou spend a weekend implementing a requested feature \u2192 crickets\nyou fix a small bug \u2192 three people thank you\nyou realize you haven't worked on your own roadmap in months \u2192 exhausting\nsomeone submits a thoughtful pr \u2192 you're not alone\nthe highs are high. the lows are low. but the people who use kaneo, who contribute, who care? they make it worth it.\nwhat i learned\n1. scope is everything\nkaneo does one thing: kanban boards. not project management. not time tracking. not team chat.\nevery feature you add is a feature you maintain forever.\nbeing clear about scope isn't limiting - it's liberating. it lets you focus. it lets you say no without guilt.\n2. automate everything you can\n# .github/workflows/ci.yml\nname: CI\non: [push, pull_request]\njobs:\n  test:\n    - run: npm test\n  security:\n    - run: npm audit\n  release:\n    - run: semantic-release\nautomation isn't lazy. it's sustainable:\n\nautomated tests catch bugs before users do\nautomated releases mean less manual work\nautomated security scans give peace of mind\nautomated dependency updates keep things current\n\nit frees you to focus on what matters.\n3. good issue templates help everyone\ngithub issue templates help people provide:\n\nsystem info\nerror logs\nsteps to reproduce\n\nit's not about gatekeeping. it's about making debugging possible. most people want to help you help them. templates make that easier.\n4. saying no is an act of respect\nyou can't build everything. saying yes to everything means doing nothing well.\nbeing honest about what you can and can't do respects everyone's time. including yours.\n5. users are collaborators\nthe people using kaneo aren't just users. they're:\n\nbeta testers finding bugs\ndocumentation editors spotting gaps\nfeature designers sharing ideas\ncommunity builders helping each other\n\nthey're not demanding. they're engaged. that's a gift.\nwhen someone opens an issue, they're investing time in making kaneo better. even if the issue is unclear, the intent is good.\npatience and kindness aren't just nice. they're necessary.\nthe honest truth\nmaintaining an open source, self-hosted project is:\n\nmore work than building it\ndifferent fun than building it\nmore rewarding than you'd expect\nharder than you'd expect\nworth it\n\nyou learn:\n\ntechnical skills (migrations, security, scalability)\npeople skills (communication, patience, boundaries)\nproduct skills (prioritization, scope, vision)\nhow to appreciate every contribution\nhow to build something people actually want\n\nmy setup (the real one)\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  kaneo infrastructure               \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502  github                             \u2502\n\u2502  \u251c\u2500 code + issues                   \u2502\n\u2502  \u251c\u2500 actions (ci/cd)                 \u2502\n\u2502  \u2514\u2500 container registry              \u2502\n\u2502                                     \u2502\n\u2502  hetzner ($7/month)                 \u2502\n\u2502  \u2514\u2500 cloud instance                  \u2502\n\u2502                                     \u2502\n\u2502  cloudflare (free)                  \u2502\n\u2502  \u2514\u2500 dns + ddos protection           \u2502\n\u2502                                     \u2502\n\u2502  plausible                          \u2502\n\u2502  \u2514\u2500 privacy-friendly analytics      \u2502\n\u2502                                     \u2502\n\u2502  coffee (priceless)                 \u2502\n\u2502  \u2514\u2500 way too much                    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nwhat i'd tell past me\n1. invest in documentation early - good docs reduce support burden and help people succeed. it's time well spent.\n2. automate from day one - tests, releases, security scans. automation scales. you don't.\n3. be clear about scope - say what your project is AND what it isn't. it helps everyone.\n4. migrations are worth the extra effort - test thoroughly. add rollbacks. write clear upgrade notes. your users trust you with their data.\n5. it's okay to be slow - you're not a company. you're a person. set expectations. take breaks. protect your energy.\n6. celebrate your users - every person using kaneo is amazing. they chose to trust something you built. that's incredible.\n7. the community is the product - the code matters, but the people matter more. invest in both.\nthe conclusion\nwould i do it again?\nabsolutely.\nkaneo exists because i wanted a simple kanban board that i controlled. but it became something more: a community of people who value privacy, simplicity, and owning their tools.\nthe maintenance is real work. the migrations are stressful. the support takes time.\nbut people are using kaneo to:\n\nrun their businesses\nmanage their side projects\norganize their teams\nlearn about self-hosting\n\nthey send thank you messages. they submit thoughtful bug reports. they contribute code. they help each other in discussions.\nthat's not just cool. that's why i do this.\n\nkaneo is open source and free forever. check it out: github.com/usekaneo/kaneo\nif you're using it, thank you. if you're contributing, you're amazing. if you're thinking about it, the docs are pretty good.\nand if you find a bug? i'll fix it. probably at 11pm. but i'll fix it."
                ],
                "output": "readability/",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:52.641368+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://andrej.sh/blog/maintaining-open-source-project/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-12-07T01:59:52.378698+00:00",
                "index_texts": null,
                "output": "What They Don't Tell You About Maintaining an Open Source Project ~ andrej acevski",
                "pwd": "/data/archive/1765072779.899126",
                "schema": "ArchiveResult",
                "start_ts": "2025-12-07T01:59:52.341084+00:00",
                "status": "succeeded"
            }
        ],
        "wget": []
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": "TimeoutExpired: Command '['/usr/bin/curl', '--silent', '--location', '--compressed', '--proxy', 'socks5://tor-socks-proxy:9150', '--head', '--max-time', '60', '--user-agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)', 'https://web.archive.org/save/https://andrej.sh/blog/maintaining-open-source-project/']' timed out after 60 seconds",
        "dom": "output.html",
        "favicon": "favicon.ico",
        "git": null,
        "media": "media/",
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "What They Don't Tell You About Maintaining an Open Source Project ~ andrej acevski",
        "warc": null,
        "wget": null
    },
    "link_dir": "/data/archive/1765072779.899126",
    "newest_archive_date": "2025-12-07T02:00:21.806766+00:00",
    "num_failures": 1,
    "num_outputs": 8,
    "oldest_archive_date": "2025-12-07T01:59:43.481504+00:00",
    "path": "/blog/maintaining-open-source-project/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_abid": "snp_01KBV8JENFF4E1A2FC016JPPYE",
    "snapshot_id": "93d1dc87-423f-4332-80ff-a2bb4d2b5bce",
    "sources": [
        "/data/sources/1765072779-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1765072779.899126",
    "title": "What They Don't Tell You About Maintaining an Open Source Project ~ andrej acevski",
    "url": "https://andrej.sh/blog/maintaining-open-source-project/"
}