# WaveHouse Cloud — full text for LLMs > Managed WaveHouse + ClickHouse: real-time analytics APIs with schema-aware ingest, SSE streaming, and tiered caching — zero ops. We run it; you ship. Source: https://wavehouse.cloud · Open source: https://github.com/Wave-RF/WaveHouse --- # WaveHouse Cloud > Managed WaveHouse + ClickHouse: real-time analytics APIs with schema-aware ingest, SSE streaming, and tiered caching — zero ops. We run it; you ship. **Supabase for ClickHouse®.** The managed platform that runs ClickHouse and the open-source WaveHouse gateway — so you ship real-time analytics APIs without operating any of the backend. - Status: Pre-launch — join the waitlist for early access. - Waitlist: https://wavehouse.cloud/#waitlist - Waitlist API: POST https://api.wavehouse.cloud/v1/waitlist with {"email": "..."} (no auth; the address owner must then click the emailed confirmation link) - Console (existing customers): https://console.wavehouse.cloud - No self-serve sign-up (closed pilot) — accounts are created by invitation. Start here: https://wavehouse.cloud/waitlist - Open-source core: https://github.com/Wave-RF/WaveHouse - Documentation: https://wavehouse.dev ## Features - **Managed ClickHouse + WaveHouse** — Both halves of the stack, run for you. We provision, secure, upgrade, back up, and scale ClickHouse and the WaveHouse gateway — you never get paged. - **Schema-aware real-time ingest** — Stream events in with async, per-table batching. WaveHouse discovers your ClickHouse schema automatically — no brittle pipelines to hand-maintain. - **Instant secure APIs** — Turn queries into named, parameterized REST endpoints with column-level authorization and bearer-token auth. From table to production API in minutes. - **Streaming + tiered caching** — Real-time SSE streaming for live dashboards, plus tiered query caching that keeps hot reads fast and your compute costs down. - **Autoscaling, usage-based** — Infrastructure that scales with your traffic and settles back down — start tiny, absorb a spike, and pay for what you actually use. - **Open-source core, no lock-in** — Built on the Apache-licensed WaveHouse project. Run it yourself anytime — Cloud is the managed convenience, never a cage. ## How it works 1. **Create a project** — Spin up a WaveHouse Cloud project and get a managed ClickHouse instance with the WaveHouse gateway already wired in front of it. 2. **Add your data** — Create your tables in the managed ClickHouse — or load data you already have. WaveHouse reads the schema directly from ClickHouse, then you define named query pipes and ingest endpoints. 3. **Ship real-time APIs** — Get secure, cached, real-time REST + streaming endpoints. Push inserts, query from anywhere, and let us handle scaling and uptime. ## The managed stack, not another box to run | DIY ClickHouse + gateway | WaveHouse Cloud | | --- | --- | | Provision and tune ClickHouse clusters | Managed, tuned, and upgraded for you | | Build and operate an API gateway | WaveHouse gateway included and run for you | | Hand-roll auth, batching, and caching | Column-level auth, async batching, tiered cache built in | | Own scaling, backups, and on-call | Autoscaling, backups, and uptime are our job | | Weeks to a production API | Minutes to a production API | ## FAQ ### What is WaveHouse Cloud? WaveHouse Cloud is Supabase for ClickHouse: a managed platform that hosts both ClickHouse and the open-source WaveHouse gateway, so you can build real-time analytics APIs without operating any of the underlying infrastructure. ### How is this different from ClickHouse Cloud or Tinybird? ClickHouse Cloud manages the database and stops there — you still build the ingest and API layer yourself. Tinybird gives you that layer, but it's closed and proprietary. WaveHouse Cloud manages both: standard ClickHouse plus the open-source WaveHouse gateway for schema-aware ingest, named API endpoints, column-level auth, and real-time SSE streaming. Think open-source Tinybird — and because the core is open source, you can self-host the exact same gateway with no lock-in. ### Is it open source? The WaveHouse gateway at the core of the service is open source (see [github.com/Wave-RF/WaveHouse](https://github.com/Wave-RF/WaveHouse)). WaveHouse Cloud is the managed hosting, scaling, and operations layer on top. ### Can I self-host instead? Yes. WaveHouse is open source and documented at [wavehouse.dev](https://wavehouse.dev). Cloud exists for teams who would rather not run ClickHouse and the gateway themselves. ### When does it launch? We're building toward launch and onboarding early users in batches. Join the waitlist and we'll email you once, when your access opens. --- # Managed ClickHouse, the way it should be > What "managed ClickHouse" really means — and why running ClickHouse plus an API gateway yourself is more work than it looks. How WaveHouse Cloud handles both. ClickHouse® is the fastest open-source database for real-time analytics. It is also a system with real operational weight: sharding and replication, schema and TTL management, backups, version upgrades, and the query tuning that keeps a busy cluster fast. Running it well is a job. Running an **API layer** in front of it — auth, batching, caching, rate limiting — is a second job. **WaveHouse Cloud does both jobs for you.** ## What "managed" should actually cover A lot of products say "managed ClickHouse" and mean "we start the database for you." That is the easy 20%. The hard 80% is everything that happens after the cluster is running: - **Ingestion that survives bursts.** Async, per-table batching so a spike in writes does not topple the cluster — without you hand-tuning insert sizes. - **Schema that stays in sync.** WaveHouse reads your schema directly from ClickHouse (`system.columns`) instead of forcing a parallel schema you have to keep aligned by hand. - **Secure APIs, not raw SQL over the wire.** Named, parameterized query pipes with column-level authorization and bearer-token auth — so your frontend never holds database credentials. - **Caching that protects your bill.** Tiered query caching keeps hot reads off the cluster, which keeps both latency and ClickHouse cost down. - **The unglamorous parts.** Backups, upgrades, scaling, and being the one who gets paged at 3am. ## Managed ClickHouse vs. running it yourself Self-hosting ClickHouse is absolutely viable — it is open source, and so is the WaveHouse gateway. The question is whether operating it is the best use of your team's time before launch. For most teams shipping a product, it is not. WaveHouse Cloud is the managed convenience: the same open-source gateway, the same standard ClickHouse, run for you on infrastructure that scales with usage. And because the core is open source, there is no lock-in — you can take the gateway and self-host it the day that calculus changes. ## Where WaveHouse fits [WaveHouse](https://wavehouse.dev) is an open-source, real-time API gateway for ClickHouse: schema-aware ingest, async batching, real-time streaming, and tiered query caching in a single binary. WaveHouse **Cloud** is that gateway plus ClickHouse, hosted and operated as one managed service. > Build the product. Let us run the analytics backend. Ready to skip the ops? [Join the waitlist](/#waitlist). --- # Privacy Policy > How WaveRF collects, uses, shares, retains, and protects information obtained through the Website. ## Introduction WaveRF, Corp. ("**WaveRF**") respects your privacy and is committed to protecting the information you provide when you visit or interact with the Website. This Privacy Policy describes how WaveRF collects, uses, shares, retains, and protects information obtained through the Website. This Privacy Policy also describes the choices available to you regarding your information and how you may contact WaveRF regarding its privacy practices. By accessing or using the Website, you acknowledge that you have read and understand this Privacy Policy. If you do not agree with this Privacy Policy, you should discontinue using the Website. This Privacy Policy applies only to information collected through the Website. It does not apply to information collected through products or services that are subject to Separate Agreements or information collected through third-party websites or services that are not owned or controlled by WaveRF. Capitalized terms used but not defined in this Privacy Policy have the meanings given to them in WaveRF's Website Terms of Use. ## Personal Information For purposes of this Privacy Policy: (a) "**Personal Information**" means information that identifies, relates to, describes, is reasonably capable of being associated with, or could reasonably be linked, directly or indirectly, with an identified or identifiable individual, and does not include information that has been deidentified, anonymized, or aggregated so that it cannot reasonably be used to identify an individual; and (b) "**Sensitive Personal Information**" means certain categories of Personal Information subject to heightened protection under applicable law, such as government identification numbers, precise geolocation, racial or ethnic origin, religious beliefs, health information, and account log-in credentials combined with the information needed to access the account. ## Information WaveRF Collects WaveRF may collect Personal Information from the following sources: ### Information You Provide WaveRF may collect Personal Information that you voluntarily provide when you contact WaveRF, request information regarding WaveRF or its products or services, subscribe to communications, submit employment inquiries, or otherwise communicate with WaveRF through the Website. Depending on how you interact with the Website, this Personal Information may include your name, company name, job title, email address, telephone number, mailing address, and the contents of your communications. ### Information Collected Automatically When you access or use the Website, WaveRF may automatically collect certain Personal Information, including your Internet Protocol (IP) address, browser type and version, operating system, device identifiers, pages visited, referring website, dates and times of access, and other information regarding your interaction with the Website. WaveRF may collect this information through cookies, web beacons, pixels, analytics technologies, and similar technologies. ### Information Received from Third Parties WaveRF may receive Personal Information from service providers, analytics providers, marketing partners, publicly available sources, or other third parties in connection with the operation of the Website or WaveRF's business. ### Platform and Account Information If you create an account or otherwise use WaveHouse or WaveRF's other management platforms, WaveRF may collect additional Personal Information, including your username and authentication credentials (or single sign-on identifiers, if you authenticate through a third-party identity provider), billing and payment information (processed through WaveRF's payment processor), organization and team membership details, device and fleet identifiers you register, and records of your configuration, usage, and administrative activity within the platform. Any payment card details are collected and processed by WaveRF's third-party payment processor and are not stored by WaveRF. ### Location and Telemetry Information WaveRF's products, including devices and software running the WaveHouse SDK, may collect and transmit telemetry data, signal-strength measurements, and location information (including GPS coordinates where available, or estimated location derived from signal-strength trilateration among nearby devices). This information may relate to the device itself or, where a device is associated with or carried by an individual (for example, in asset-tracking or personnel-tracking deployments), to that individual. Where WaveRF's customer, rather than the individual, controls the deployment of such devices, that customer is responsible for providing appropriate notice to and, where required by applicable law, obtaining consent from individuals whose location or telemetry data is collected through the customer's use of WaveRF's products. WaveRF's products may use automated processes, such as network routing and device positioning, to operate. See the Section entitled "Your Privacy Rights" below for information about rights that may apply to automated decision-making. ### Sensitive Personal Information WaveRF does not intentionally collect Sensitive Personal Information through the Website except where voluntarily provided by you, where it is necessary to provide a product or service that you have requested (including the location and telemetry information described above), or where it is required in connection with an employment inquiry you submit. Unless specifically requested by WaveRF, you should not submit Sensitive Personal Information through the Website beyond what is necessary for these purposes. ## How WaveRF Uses Personal Information WaveRF may use Personal Information for the following purposes: (a) to operate, maintain, and improve the Website; (b) to create and administer your account, authenticate your access, and provide the products and services you request, including billing and subscription management; (c) to provide network routing, fleet management, telemetry, and location or positioning features that you or your organization has enabled through WaveHouse or the WaveHouse SDK; (d) to respond to your inquiries, requests, and communications; (e) to provide information regarding WaveRF and its technologies, products, and services; (f) to administer communications, subscriptions, newsletters, events, or other programs that you elect to receive; (g) to monitor, analyze, and improve the performance, functionality, security, and usability of the Website; (h) to detect, investigate, prevent, or respond to fraud, unauthorized access, security incidents, or other unlawful or prohibited activities; (i) to comply with applicable law, rule, regulation, legal process, court order, subpoena, governmental request, or a contractual obligation; (j) to establish, exercise, or defend legal claims; (k) for any other purpose disclosed at the time Personal Information is collected; and (l) with your consent or at your direction. ## Cookies and Similar Technologies WaveRF may use cookies, web beacons, pixels, analytics technologies, and similar technologies to operate the Website, improve functionality, analyze Website traffic, understand how visitors use the Website, and enhance the user experience. Most web browsers permit you to control or disable cookies through your browser settings. If you disable cookies, certain features or functionality of the Website may not operate properly. The Website may use third-party analytics providers or similar service providers that use cookies or similar technologies to collect information regarding your use of the Website. Any information collected by those third parties is governed by their applicable privacy policies. Some browsers offer a "Do Not Track" signal. Because there is no common industry standard for interpreting this signal, the Website does not currently respond to it. WaveRF does honor the Global Privacy Control and other opt-out preference signals as described in the "Your Privacy Rights" Section, to the extent required by applicable law. ## How WaveRF Shares Personal Information WaveRF does not sell Personal Information and does not "share" Personal Information (as that term is defined under applicable law), except as described in this Section. WaveRF may disclose Personal Information in the following circumstances: (a) to service providers, contractors, consultants, and other third parties that perform services on WaveRF's behalf and that require access to Personal Information to perform those services; (b) to WaveRF's affiliates in connection with the operation of WaveRF's business; (c) in connection with a merger, acquisition, financing, corporate reorganization, sale of assets, bankruptcy, or other business transaction involving all or a portion of WaveRF's business or assets; (d) to comply with applicable law, rule, regulation, legal process, court order, subpoena, governmental request, or a contractual obligation; (e) to establish, exercise, or defend the legal rights of WaveRF or others; (f) to detect, investigate, prevent, or respond to fraud, security incidents, or other unlawful activity; (g) with your consent or at your direction; or (h) to third-party analytics or advertising partners that use cookies or similar technologies described in the Section entitled "Cookies and Similar Technologies," to the extent that such use constitutes a "sale" or "sharing" of Personal Information under applicable law. WaveRF may also disclose information that has been deidentified, anonymized, or aggregated so that it does not reasonably identify any individual. ## Data Retention WaveRF retains Personal Information only for as long as reasonably necessary to fulfill the purposes described in this Privacy Policy, comply with applicable legal obligations, resolve disputes, enforce agreements, or satisfy other legitimate business purposes. The length of time Personal Information is retained depends on the nature of the information, the purpose for which it was collected, and applicable legal, regulatory, contractual, and operational requirements. Personal Information processed in connection with a Beta Feature may be subject to additional logging and monitoring for testing and debugging purposes and may not follow the same retention or deletion practices described in this Section. WaveRF will use reasonable efforts to delete such information when it is no longer needed for the applicable testing purpose. ## Data Security WaveRF maintains reasonable administrative, technical, and physical safeguards designed to protect Personal Information from unauthorized access, use, disclosure, alteration, or destruction. No method of transmitting information over the Internet or storing information electronically is completely secure. Accordingly, WaveRF cannot guarantee the security of Personal Information. If WaveRF becomes aware of a security incident involving unauthorized access to or acquisition of Personal Information that requires notification under applicable law, WaveRF will notify affected individuals and, where required, applicable regulators within the timeframe required by applicable law, and will describe the nature of the incident and the steps WaveRF is taking in response. ## Your Privacy Rights Subject to applicable law, and depending on your jurisdiction, you may have certain rights regarding your Personal Information, including the right to: (a) request access to the Personal Information WaveRF maintains about you; (b) request that inaccurate or incomplete Personal Information be corrected; (c) request that WaveRF delete Personal Information, subject to applicable legal exceptions; (d) request a copy of the Personal Information you have provided to WaveRF in a structured, commonly used, and machine-readable format, and, where technically feasible, request that WaveRF transmit that information to another entity; (e) object to or request restrictions on certain processing of Personal Information where permitted by applicable law; (f) withdraw any consent you have previously provided, where WaveRF's processing is based on your consent; (g) opt out of the "sale" or "sharing" of Personal Information, to the extent WaveRF engages in either as described in the Section entitled "How WaveRF Shares Personal Information"; (h) not receive discriminatory treatment for exercising any of the foregoing rights; and (i) request human review of, or object to, a decision based solely on automated processing that produces legal or similarly significant effects concerning you, where applicable law provides this right. To exercise any applicable privacy rights or submit a privacy-related request, please contact WaveRF using the contact information provided at the end of this Privacy Policy. WaveRF may request additional information to verify your identity before responding to your request. WaveRF will respond to verifiable requests within the time period required by applicable law (typically 45 days, subject to a permitted extension). If WaveRF denies your request in whole or in part, you may have the right to appeal that decision using the same contact information. Where required by applicable law, WaveRF will treat an opt-out preference signal (such as the Global Privacy Control) received from your browser as a valid request to opt out of the sale or sharing of Personal Information collected during that browser session. If you are located in the European Economic Area, the United Kingdom, or Switzerland, see the Section entitled "International Users" below for the legal bases for this processing. ## International Users The Website is operated from the United States. If you access the Website from outside the United States, you acknowledge that your Personal Information may be transferred to, processed, and stored in the United States, where privacy laws may differ from those of your jurisdiction. If you are located in the European Economic Area, the United Kingdom, or Switzerland, WaveRF processes your Personal Information on the following legal bases: the performance of a contract with you, WaveRF's legitimate interests in operating, securing, and improving the Website, compliance with legal obligations, and your consent where required. Where WaveRF transfers Personal Information from these regions to the United States or other countries, it does so under appropriate safeguards, including the European Commission's Standard Contractual Clauses or another valid transfer mechanism recognized under applicable law. You have the right to lodge a complaint with your local data protection supervisory authority. ## Children's Privacy The Website is not directed to children under 13 years of age, and WaveRF does not knowingly collect Personal Information from children under 13 through the Website. If WaveRF becomes aware that it has collected Personal Information from a child under 13 without appropriate parental consent, WaveRF will take reasonable steps to delete such information. If you believe that a child under 13 has provided Personal Information to WaveRF through the Website, please contact WaveRF using the contact information provided at the end of this Privacy Policy. ## Third-Party Websites The Website may contain links to third-party websites or services that are not owned or controlled by WaveRF. This Privacy Policy does not apply to those third-party websites or services. WaveRF encourages you to review the privacy policies of any third-party website or service you visit before providing any Personal Information. ## Changes to this Privacy Policy WaveRF may update this Privacy Policy from time to time. If WaveRF makes changes to this Privacy Policy, WaveRF will post the revised Privacy Policy on the Website and update the above "Effective Date". Unless otherwise stated, the revised Privacy Policy will become effective immediately upon posting. Your continued use of the Website after the revised Privacy Policy becomes effective constitutes your acceptance of the revised Privacy Policy. ## Contact WaveRF If you have any questions regarding this Privacy Policy or WaveRF's privacy practices, please contact WaveRF at [privacy@wave-rf.com](mailto:privacy@wave-rf.com). --- # Security > How to report a vulnerability in WaveHouse Cloud, and our approach to security for the pre-launch site. We take security seriously, even before launch. If you believe you've found a vulnerability in this website or its waitlist infrastructure, we want to hear from you. ## Reporting a vulnerability Email **[security@wavehouse.cloud](mailto:security@wavehouse.cloud)** with details and, if possible, steps to reproduce. We aim to acknowledge reports within a few business days. A machine-readable policy is published at [`/.well-known/security.txt`](/.well-known/security.txt) per [RFC 9116](https://www.rfc-editor.org/rfc/rfc9116). ## Reporting abuse of a customer endpoint Each WaveHouse Cloud project is served from its own subdomain of **wavehouse.app**, and the content returned there is defined by the customer who owns that project — not by us. If a `.wavehouse.app` endpoint is serving phishing pages, malware, or anything else malicious, report it to **[abuse@wavehouse.cloud](mailto:abuse@wavehouse.cloud)** with the full hostname and, where possible, a URL or capture. We act on abuse reports on the same timeline as vulnerability reports. Use this address rather than the one above — a tenant abusing the platform and a flaw in our own software are different problems with different responses. Our own site, console, API and documentation are on **wavehouse.cloud**, a deliberately separate registrable domain; nothing customer-controlled is ever served from it. ## Safe harbor We will not pursue legal action for good-faith security research that: - respects user privacy and avoids degrading the service, - does not access or modify data that isn't yours, - gives us a reasonable chance to remediate before public disclosure. Please **do not** run automated scanners that flood the waitlist, attempt denial of service, or social-engineer our team. ## Our posture - The site is static and served over HTTPS on Cloudflare; the only write path is the waitlist endpoint, which is rate-limited and deduplicated. It is deliberately open (no CAPTCHA) so agents acting on a person's behalf can sign them up; email confirmation (double opt-in) is the planned abuse control. - We collect the minimum data needed (your email plus signup context). Your IP address is used to rate-limit requests and protect the service, and may appear in short-lived operational logs. - The open-source WaveHouse project has its own security model documented in its [repository](https://github.com/Wave-RF/WaveHouse). --- # Terms of Use > The terms that govern your access to and use of WaveRF's websites, web applications, dashboards, and management platforms. ## Acceptance of Terms These Website Terms of Use (these "**Terms**") constitute a legally binding agreement between WaveRF, Corp. ("**WaveRF**") and each individual or entity that accesses or uses the Website (as defined below) ("**you**" or "**your**"). These Terms govern your access to and use of any and all websites, web applications, dashboards, and management platforms owned or operated by WaveRF that post or link to these Terms, including WaveHouse and any associated APIs made generally available without a Separate Agreement (defined below) (collectively, the "**Website**"). By accessing or using the Website, you acknowledge that you have read and understand these Terms and agree to be bound by them. You also acknowledge that you have read and understand WaveRF's Privacy Policy, which is incorporated into these Terms by reference (the "**Privacy Policy**"). If you do not agree to these Terms or the Privacy Policy, you must immediately discontinue all access to and use of the Website. If you access or use the Website on behalf of a corporation, limited liability company, partnership, governmental entity, or other legal entity, you represent and warrant that you have the full power and authority to bind that entity to these Terms. In such a case, the terms "**you**" and "**your**" refer to both you individually and the entity on whose behalf you are acting. The Website is intended for individuals who are at least 18 years of age or the age of legal majority in their jurisdiction of residence, whichever is greater. By accessing or using the Website, you represent and warrant that you satisfy the foregoing requirement and are legally competent to enter into these Terms. ## Changes to Terms and Website WaveRF may revise these Terms from time to time in its sole discretion. If WaveRF revises these Terms, it will post the updated version on the Website and update the above "Effective Date". Unless otherwise stated in the revised Terms, the revised Terms will become effective immediately upon posting. Your continued access to or use of the Website after the revised Terms become effective constitutes your acceptance of the revised Terms. If you do not agree to any revised Terms, you must discontinue accessing and using the Website. WaveRF may, at any time and without prior notice, modify, update, suspend, discontinue, or remove all or any portion of the Website, including any Content, products, or services made available through the Website. WaveRF will have no liability arising from any modification, suspension, discontinuance, or removal of the Website or any portion thereof. ## Access to Website Subject to your compliance with these Terms, WaveRF grants you a limited, personal, non-exclusive, non-transferable, non-sublicensable, and revocable right to access and use the Website solely for your own lawful informational and business purposes. Except for the limited right to access and use the Website expressly granted in these Terms, no right, title, or interest in or to the Website is granted to you. WaveRF does not guarantee that the Website, or any Content or functionality available through the Website, will always be available, uninterrupted, secure, error-free, or compatible with your hardware, software, browser, or device. WaveRF may suspend, restrict, or terminate your access to all or any portion of the Website at any time if WaveRF reasonably determines that: (a) you have violated these Terms or applicable law; (b) your use of the Website poses a security risk to the Website, WaveRF, or any third party; (c) your use of the Website could subject WaveRF or any third party to liability; or (d) such action is reasonably necessary to protect the Website or the rights, property, or safety of WaveRF or others. ## Intellectual Property Rights For the purposes of these Terms, "**Content**" means all information, text, graphics, photographs, images, illustrations, audio, video, documentation, downloads, data, databases, compilations, logos, trademarks, service marks, trade names, trade dress, icons, software, source code, object code, designs, layouts, interfaces, and other content or materials made available on or through the Website. The Website and all Content, together with the selection, arrangement, coordination, compilation, and overall appearance thereof, are owned by or licensed to WaveRF and are protected by United States and international copyright, trademark, patent, trade secret, and other intellectual property and proprietary rights laws. No portion of the Website or any Content may be copied, reproduced, republished, uploaded, posted, publicly displayed, publicly performed, encoded, translated, transmitted, distributed, sold, licensed, rented, leased, reverse engineered, decompiled, disassembled, or exploited without WaveRF's prior written consent. Except for the limited right to access and use the Website expressly granted in these Terms, all right, title, and interest in and to the Website and the Content are reserved by WaveRF and its licensors. Nothing contained in these Terms or on the Website grants any ownership interest, license, or other right in or to the Website, the Content, or any intellectual property of WaveRF or its licensors except as expressly provided in these Terms. You may not remove, alter, obscure, or conceal any copyright, trademark, proprietary, or other notices appearing on the Website or any Content. Any unauthorized use of the Website or the Content may violate copyright, trademark, patent, trade secret, or other applicable laws and may result in civil or criminal penalties. Notwithstanding the foregoing, certain WaveRF software, including any software and/or SDK that WaveRF makes available through public repositories (e.g., GitHub), is offered under a separate open-source license specified in that repository. To the extent of any conflict between these Terms and the applicable open-source license for such software, the open-source license will govern solely with respect to that software. ## Trademarks The WaveRF name and logo, and all related names, logos, product names, service names, slogans, trade dress, and other indicia of source displayed on the Website, are trademarks, service marks, or other proprietary identifiers of WaveRF or its licensors (each, a "**Mark**"). You may not use any Mark in connection with any product, service, website, advertisement, social media account, or other activity that is likely to cause confusion regarding the source, sponsorship, affiliation, or endorsement of any product or service, or that disparages or dilutes the goodwill associated with any Mark. All other trademarks, service marks, logos, and trade names appearing on the Website are the property of their respective owners. Reference to any third-party name, product, or service does not imply any affiliation with, endorsement by, or sponsorship of WaveRF unless expressly otherwise stated. ## Prohibited Uses You may use the Website only for lawful purposes and in accordance with these Terms. Without limiting the foregoing, you may not, and may not permit any third party to: (a) use the Website in violation of any applicable federal, state, local, or foreign law, rule, or regulation; (b) access or use the Website in any manner that could damage, disable, overburden, impair, or interfere with the Website or any other person's or entity's use of the Website; (c) attempt to gain unauthorized access to any portion of the Website, any server on which the Website is hosted, or any systems or networks connected to the Website; (d) introduce or transmit any virus, worm, Trojan horse, malware, ransomware, spyware, or other malicious code or technology; (e) probe, scan, test, or assess the vulnerability of the Website or any related system or network, or circumvent or attempt to circumvent any security or authentication measures, except with WaveRF's prior written authorization; (f) use any robot, spider, crawler, scraper, data mining tool, artificial intelligence agent, automated script, or other automated means to access, monitor, copy, index, harvest, or extract any portion of the Website or its Content, except for standard search engine indexing conducted in accordance with applicable robots.txt instructions; (g) use any Content to train, develop, ingest, fine-tune, validate, benchmark, generate datasets, evaluate, or improve any artificial intelligence, machine learning, large language model, or similar technology without WaveRF's prior written consent; (h) frame, mirror, or incorporate any portion of the Website into another website, application, or service; (i) use the Website for the purpose of developing, marketing, supporting, or improving any product or service that competes with WaveRF or the Website; (j) misrepresent your identity or affiliation with any person or entity; (k) interfere with or disrupt the integrity, security, or performance of the Website or any systems or networks used to provide the Website; or (l) encourage, facilitate, or assist any other person or entity in engaging in any of the foregoing activities. WaveRF reserves the right to investigate any suspected violation of this Section and to take any action it reasonably determines is appropriate, including suspending or terminating access to the Website, reporting suspected unlawful activity to law enforcement authorities, or pursuing any other remedies available at law or in equity. WaveRF welcomes reports of good-faith security research and vulnerability findings. Nothing in subsection (e) above prohibits security research conducted in accordance with WaveRF's responsible disclosure practices. Researchers seeking authorization to conduct such research, or wishing to report a suspected vulnerability, should contact WaveRF at [legal@wave-rf.com](mailto:legal@wave-rf.com). ## Export Control and Sanctions Compliance The Website, the Content, and any related software or technology may be subject to U.S. export control and economic sanctions laws, including the Export Administration Regulations (EAR) and regulations administered by the U.S. Department of the Treasury's Office of Foreign Assets Control (OFAC). You represent and warrant that you are not located in, organized under the laws of, or ordinarily resident in any country or territory subject to comprehensive U.S. sanctions, and that you are not identified on any U.S. government list of restricted, denied, or prohibited parties. You agree not to access or use the Website, or export, re-export, or transfer any Content or technology obtained through the Website, in violation of any applicable export control or sanctions law. ## U.S. Government End Users If the Website, the Content, or any related software is accessed or used by or on behalf of the United States Government, the Website and such Content and software are provided as "commercial computer software" and "commercial computer software documentation" as those terms are defined in 48 C.F.R. § 2.101, and are licensed to U.S. Government end users only as commercial items and with only those rights as are granted to all other users pursuant to these Terms, in accordance with 48 C.F.R. § 12.212 and 48 C.F.R. §§ 227.7202-1 through 227.7202-4, as applicable. ## Feedback The Website may permit you to contact WaveRF, request information, subscribe to communications, submit employment inquiries, or transmit information to WaveRF. You are solely responsible for the accuracy, legality, and appropriateness of any information you submit through the Website. Except for Personal Information (as defined in the Privacy Policy) governed by the Privacy Policy or information that is subject to a separate written confidentiality agreement with WaveRF, any comments, suggestions, ideas, feedback, recommendations, or other information you voluntarily submit to WaveRF regarding the Website, the Content, WaveRF's business, or WaveRF's products or services (collectively, "**Feedback**") will be deemed non-confidential and non-proprietary. By submitting any Feedback, you grant WaveRF a perpetual, irrevocable, worldwide, transferable, sublicensable, royalty-free, and fully paid-up right and license to use, reproduce, modify, adapt, publish, translate, distribute, perform, display, create derivative works from, commercialize, and exploit such Feedback for any lawful purpose without acknowledgment, compensation, or any other obligation to you. You represent and warrant that: (a) you own or have all necessary rights to submit any Feedback; (b) your submission does not violate any applicable law or the rights of any third party; and (c) your submission does not contain any malicious code or other harmful material. ## Third-Party Websites The Website may contain links to third-party websites, applications, products, services, or other resources that are provided solely for your convenience. Such third-party resources are not owned or controlled by WaveRF, and WaveRF does not endorse or assume responsibility for their content, products, services, policies, or practices. WaveRF does not monitor such third-party resources and makes no representations regarding their availability or security. If you choose to access any third-party website or resource, you do so entirely at your own risk and subject to the terms and conditions and privacy policies applicable to such third party. WaveRF will not be responsible or liable for any loss or damage arising from or relating to your access to or use of any third-party website or resource. ## Separate Agreements The Website is intended to provide general information regarding WaveRF and its technologies, products, and services. Certain products, software, hardware, applications, downloads, subscriptions, professional services, support services, or other offerings referenced on the Website may be subject to separate agreements, including order forms, purchase orders, software license agreements, subscription agreements, statements of work, service level agreements, professional services agreements, or other written terms (each, a "**Separate Agreement**" and collectively, "**Separate Agreements**"). To the extent applicable, your purchase of, license to, subscription to, or use of any product or service offered by WaveRF will be governed by one or more Separate Agreements. Those Separate Agreements will govern the applicable product or service and, to the extent of any conflict with these Terms, will control solely with respect to the applicable product or service. Nothing contained in these Terms modifies, supersedes, or amends any Separate Agreement. ## Beta and Pre-Release Features From time to time, WaveRF may make available features, products, or services that are identified as "beta," "preview," "early access," or by similar designation (each, a "**Beta Feature**" and collectively, "**Beta Features**"). Beta Features are provided for evaluation purposes only, may not be complete or fully functional, and may contain errors or inaccuracies. WaveRF may modify or discontinue any Beta Feature, or the data associated with it, at any time without notice and without liability. You acknowledge that the use of a Beta Feature is at your own risk, that data created, stored, or processed using a Beta Feature may be lost, corrupted, or become unavailable, and that Beta Features are provided "as is" without any representation or warranty of any kind, notwithstanding anything else to the contrary in these Terms. ## Website Information; No Offer The Website and the Content are provided solely for general informational purposes. Nothing contained on the Website constitutes or will be deemed to constitute: (a) an offer to sell, license, or provide any product or service; (b) a binding quotation or proposal; (c) a commitment to develop, release, continue, or support any product, feature, functionality, or service; or (d) engineering, technical, legal, regulatory, financial, or other professional advice. Product descriptions, technical specifications, compatibility information, demonstrations, screenshots, illustrations, performance metrics, availability, pricing, product roadmaps, and other information appearing on the Website are subject to change without notice and are provided for informational purposes only. Certain statements on the Website, including references to uptime percentages, guaranteed delivery, or similar performance characterizations, describe target design objectives of WaveRF's technology and are not warranties, service level commitments, or guarantees of actual performance. Any binding service level commitment applicable to a specific product or service will be set forth exclusively in the applicable Separate Agreement and will supersede any general statements made on the Website. The Website may describe anticipated products, features, functionality, technologies, or services that have not yet been released or may never become available. Any such descriptions reflect WaveRF's current development objectives only and do not constitute a representation, warranty, promise, or commitment that any such product, feature, functionality, technology, or service will be developed or offered or will continue to be available. Although WaveRF strives to keep the Website current and accurate, WaveRF does not represent or warrant that the Website or any Content is complete, accurate, current, reliable, or free from errors or omissions. You are solely responsible for evaluating the accuracy, completeness, and usefulness of any information made available through the Website before relying upon it. WaveRF is under no obligation to provide any technical support, maintenance, updates, upgrades, or bug fixes in connection with the Website or any Content, except to the extent expressly required by a Separate Agreement. Any support WaveRF elects to provide absent a Separate Agreement is provided on a courtesy basis only and may be discontinued at any time without notice or liability. ## High-Risk and Safety-Critical Use The Website and the Content are not intended to support the design, deployment, or operation of any safety-critical, life-safety, or high-risk system, including systems used in aviation, aerospace, medical treatment, emergency response, nuclear facilities, or critical infrastructure, where any failure could result in death, personal injury, or severe property or environmental damage ("**High-Risk Use**"). Any decision to use WaveRF's technologies, products, or services in connection with a High-Risk Use, and the terms governing any such use, must be expressly addressed in a Separate Agreement. Absent such a Separate Agreement, WaveRF makes no representation, warranty, or commitment that the Website, the Content, or any product or service described on the Website is suitable for High-Risk Use, and you assume full responsibility for any such use. ## Copyright Claims If you believe that material available on the Website infringes your copyright, you may submit a notice to WaveRF's designated agent in accordance with the Digital Millennium Copyright Act, 17 U.S.C. § 512, including: (a) a description of the copyrighted work claimed to have been infringed; (b) a description of the material you claim is infringing and its location on the Website; (c) your contact information, including address, telephone number, and email address; (d) a statement that you have a good faith belief that the use is not authorized by the copyright owner, its agent, or the law; (e) a statement, made under penalty of perjury, that the information in the notice is accurate and that you are authorized to act on behalf of the copyright owner; and (f) your physical or electronic signature. Notices should be sent to WaveRF's designated copyright agent at: Copyright Agent, Legal Department, WaveRF, Corp., 333 Jackson Plaza, Suite 601, Ann Arbor, Michigan 48103, or [legal@wave-rf.com](mailto:legal@wave-rf.com). WaveRF may remove or disable access to material in response to a valid notice and may terminate the accounts of repeat infringers in appropriate circumstances. ## Electronic Communications By communicating with WaveRF through the Website or by sending emails or other electronic communications to WaveRF, you consent to receive communications from WaveRF electronically. WaveRF may provide notices, disclosures, and other communications electronically, including by posting them on the Website or sending them to the email address you provide. You agree that all agreements, notices, disclosures, and other communications that WaveRF provides electronically satisfy any legal requirement that such communications be in writing. ## Disclaimer of Warranties THE WEBSITE AND ALL CONTENT ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, WAVERF DISCLAIMS ANY AND ALL REPRESENTATIONS AND WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, ACCURACY, COMPLETENESS, RELIABILITY, AVAILABILITY, QUIET ENJOYMENT, AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE, OR USAGE OF TRADE. WITHOUT LIMITING THE FOREGOING, WAVERF DOES NOT REPRESENT OR WARRANT THAT: (A) THE WEBSITE WILL BE AVAILABLE AT ANY PARTICULAR TIME OR LOCATION; (B) ACCESS TO THE WEBSITE WILL BE UNINTERRUPTED, TIMELY, SECURE, OR ERROR-FREE; (C) THE WEBSITE OR ANY CONTENT WILL BE ACCURATE, COMPLETE, CURRENT, OR RELIABLE; (D) ANY DEFECTS OR ERRORS WILL BE CORRECTED; OR (E) THE WEBSITE OR ANY SERVER FROM WHICH THE WEBSITE IS MADE AVAILABLE IS FREE OF VIRUSES, MALWARE, OR OTHER HARMFUL COMPONENTS. YOUR ACCESS TO AND USE OF THE WEBSITE IS AT YOUR SOLE RISK. Any reference on the Website to "guaranteed," "guarantee," specific uptime percentages, or similar terms describes a design objective only and do not constitute a warranty or contractual commitment absent an express, signed Separate Agreement stating otherwise. Some jurisdictions do not allow the exclusion of implied warranties SET FORTH ABOVE, so some or all of the exclusions in this Section may not apply to you. In SUCH A case, any implied warranties will be limited to the shortest period and narrowest scope permitted by applicable law. ## Limitation of Liability TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, WAVERF, ITS AFFILIATES, AND ITS AND THEIR RESPECTIVE DIRECTORS, OFFICERS, MANAGERS, EMPLOYEES, AGENTS, REPRESENTATIVES, LICENSORS, SERVICE PROVIDERS, SUCCESSORS, AND ASSIGNS WILL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, EXEMPLARY, PUNITIVE, OR ENHANCED DAMAGES, OR FOR ANY LOSS OF PROFITS, REVENUE, BUSINESS OPPORTUNITY, GOODWILL, USE, DATA, OR BUSINESS INTERRUPTION, ARISING OUT OF OR RELATING TO THE WEBSITE, THE CONTENT, THESE TERMS, OR YOUR ACCESS TO OR USE OF, OR YOUR INABILITY TO ACCESS OR USE, THE WEBSITE, REGARDLESS OF THE LEGAL THEORY ASSERTED AND EVEN IF WAVERF HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Some jurisdictions do not allow the LIMITATION OR exclusion of LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES SET FORTH ABOVE, so some or all of the LIMITATIONS in this Section may not apply to you. In SUCH A case, WAVERF'S LIABILITY WILL BE LIMITED TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE AGGREGATE LIABILITY OF WAVERF ARISING OUT OF OR RELATING TO THE WEBSITE, THE CONTENT, OR THESE TERMS WILL NOT EXCEED US$100. THE LIMITATIONS SET FORTH IN THIS SECTION FORM AN ESSENTIAL BASIS OF THE BARGAIN BETWEEN YOU AND WAVERF AND WILL APPLY EVEN IF ANY LIMITED REMEDY FAILS OF ITS ESSENTIAL PURPOSE. ## Indemnification You agree to defend, indemnify, and hold harmless WaveRF, its affiliates, and its and their respective directors, officers, managers, employees, agents, representatives, licensors, service providers, successors, and assigns from and against any and all claims, demands, actions, proceedings, liabilities, obligations, damages, judgments, losses, fees, costs, and expenses (including reasonable attorneys' fees) arising out of or relating to: (a) your access to or use of the Website; (b) your violation of these Terms; (c) your violation of any applicable law or the rights of any third party, including your misappropriation or infringement of any intellectual property; or (d) any Feedback submitted by you through the Website. WaveRF reserves the right, at its own expense, to assume the exclusive defense and control of any matter subject to indemnification by you under this Section. In such a case, you will reasonably cooperate with WaveRF in the defense of the applicable claim. ## Governing Law and Jurisdiction These Terms and any dispute, claim, or controversy arising out of or relating to these Terms or the Website, whether based in contract, tort, statute, or otherwise, will be governed by and construed in accordance with the laws of the State of Delaware, without giving effect to any choice or conflict of law provision or rule that would require the application of the laws of another jurisdiction. Subject to applicable law, you irrevocably submit to the exclusive jurisdiction of the state courts located in Washtenaw County, Michigan and the United States District Court for the Eastern District of Michigan for the resolution of any dispute arising out of or relating to these Terms or the Website. You waive any objection based on improper venue or forum non conveniens with respect to such courts. ## Miscellaneous These Terms constitute the entire agreement between you and WaveRF with respect to your access to and use of the Website and supersede all prior or contemporaneous understandings, agreements, representations, and warranties relating to the Website. If any provision of these Terms is held to be invalid, illegal, or unenforceable by a court of competent jurisdiction, that provision will be enforced to the maximum extent permitted by applicable law, and the remaining provisions of these Terms will remain in full force and effect. WaveRF's failure to exercise or enforce any right or provision of these Terms will not constitute a waiver of that right or provision or of any other right or provision. You may not assign or transfer these Terms or any of your rights or obligations under these Terms without WaveRF's prior written consent. Any attempted assignment in violation of this Section will be void. WaveRF may assign these Terms, in whole or in part, without restriction at any time. Any notice required or permitted under these Terms (other than a copyright infringement notice, which is governed by the Section entitled "Copyright Claims") must be in writing and sent to WaveRF at [legal@wave-rf.com](mailto:legal@wave-rf.com), or to you at the email address or contact information you have most recently provided to WaveRF. Notices will be deemed given when sent, provided that a notice sent by email will be deemed given on the next business day if sent outside WaveRF's normal business hours. WaveRF will not be liable for any delay or failure to perform resulting from causes beyond its reasonable control, including acts of God, natural disasters, war, terrorism, civil unrest, labor disputes, failures of telecommunications or internet service providers, power outages, governmental actions, epidemics or pandemics, or other events beyond WaveRF's reasonable control. Nothing in these Terms creates or will be construed as creating any agency, partnership, joint venture, employment, fiduciary, or other similar relationship between you and WaveRF. These Terms are for the sole benefit of the parties and do not confer any rights or remedies upon any other person or entity except as expressly provided in these Terms. The headings used in these Terms are provided solely for convenience and will not affect the interpretation of these Terms. The words "including," "include," and "includes" mean "including, without limitation". ## Contact WaveRF If you have any questions regarding these Terms, please contact WaveRF at [legal@wave-rf.com](mailto:legal@wave-rf.com). --- # Routing Subcommands in WaveHouse: switch, Cobra, or Kong? > Why a hand-written switch still routes WaveHouse's CLI, what a library would actually buy us, and which one gets my vote. _2026-08-27 · Taite Lee_ *No generative AI was used at any point during the writing of this blog post. Written and edited by humans in Michigan.* Go projects like [WaveHouse](https://wavehouse.dev) that ship a binary with any sort of command line interface (CLI) often face the same question: pull in [Cobra](https://github.com/spf13/cobra)? Maybe use [Kong](https://github.com/alecthomas/kong)? Or, do we keep writing the argument handling ourselves? In my experience, the answer usually gets decided on a whim, and without what I’d consider *adequate* justification. I typically see people just stick with whatever option that they’re most familiar with. As long as they don’t run into any problems along the way, it usually works out. But as we started working on the CLI for WaveHouse, I wanted to pick an implementation method that, you know, made sense! So, I took some time to figure out exactly what our CLI needed to do, what we already have for free, and what each library would change. Here is a snippet from `cmd/wavehouse/main.go`: ```go func main() { // Subcommand dispatch. `health` self-probes /livez for the distroless // Dockerfile HEALTHCHECK; `validate` checks a settings directory without // starting the server; `bootstrap` writes a starter one. An unknown command is a usage error // and it must never fall through and silently start the server (`wavehouse validat` // booting a listener is not a typo anyone wants). The switch only routes; // each subcommand owns a stdlib flag.FlagSet, so `wavehouse -h` // prints command-specific help and a stray flag or argument is a usage // error. If the command surface outgrows this (nested subcommands, shared // persistent flags), port the switch to cobra or kong. if len(os.Args) > 1 { switch os.Args[1] { case "health": os.Exit(runHealthCheck(os.Args[2:])) case "validate": os.Exit(runValidate(os.Args[2:])) case "bootstrap": os.Exit(runBootstrap(os.Args[2:])) case "version", "--version", "-v": fmt.Printf("wavehouse %s (commit %s, built %s)\n", Version, GitCommit, BuildTime) os.Exit(0) case "help", "--help", "-h": printUsage(os.Stdout) os.Exit(0) default: fmt.Fprintf(os.Stderr, "wavehouse: unknown command %q\n\n", os.Args[1]) printUsage(os.Stderr) os.Exit(2) } } os.Exit(run()) } ``` In the snippet above, running WaveHouse without any arguments will just start the server. Running WaveHouse with a specified subcommand will initiate one of these jobs instead: ```text wavehouse start the server wavehouse validate [dir] validate a settings directory wavehouse bootstrap write a starter settings directory wavehouse health probe /livez (the Docker HEALTHCHECK) wavehouse version ``` To implement the routing for the subcommands, I referred back to the classic Args parsing I learned in one of my core CS courses. It’s simple: first check if an arg exists after the WaveHouse command. If an arg does exist, check what it reads (note that we have a switch case on `Args[1]` for the index of the subcommand). Depending on what the subcommand arg reads, we can perform different actions. If we reach the default case, we have not identified the subcommand as one of our listed options. ```mermaid flowchart TD accTitle: How main() routes a command line accDescr: If there is no argument after wavehouse, run starts the server. Otherwise os.Args[1] is switched on: validate, health and bootstrap each hand os.Args[2:] to their own function, whose FlagSet parses the remaining args; version and help print and exit 0; anything else prints usage and exits 2. start([wavehouse ...]):::neutral --> hasArg{Any argument
after wavehouse?} hasArg -- no --> serve[run: start the server]:::wh hasArg -- yes --> which{What is os.Args#91;1#93;?} which -- validate --> validate["runValidate os.Args[2:]"]:::wh which -- health --> health["runHealthCheck os.Args[2:]"]:::wh which -- bootstrap --> bootstrap["runBootstrap os.Args[2:]"]:::wh which -- version / help --> printExit[print and exit 0]:::neutral which -- anything else --> unknown[unknown command
print usage, exit 2]:::fail validate --> flagset[that subcommand's FlagSet
parses the remaining args]:::infra health --> flagset bootstrap --> flagset ``` *How `main()` routes a command line. Only `os.Args[1]` is inspected here; everything after it belongs to the subcommand.* The switch only decides which subcommand runs though, so it doesn’t look at anything past the subcommand index, like possible arguments. Everything after the subcommand is just passed into the subcommand function. Each subcommand has its own `flag.FlagSet`, which is an argument parser for that specific subcommand. The parser defines the subcommand's flag definitions, prints the subcommand's own help menu, rejects flags that aren't recognized, and returns the positional arguments (like validate's `[dir]`). But none of our subcommands define any flags at this point, so why does this even matter? Because it’s a foundation. In this setup, adding a `--strict` flag in the future only takes one line of code inside our validate function. But for now, FlagSet works in the background, handling help requests and catching typos. I’m sure it could seem like I’m trying to argue that not using a library is the way to go for WaveHouse, but I can assure you this is not my intention. What I am trying to do is clearly identify our design requirements before evaluating the possible options. Before comparing any of the alternatives, though, there's one requirement that has to come first, because it decides whether an option is even on the table. > “An unknown command is a usage error — it must never fall through and silently start the server (`wavehouse validat` booting a listener is not a typo anyone wants).” — Comment from our `main.go` Because WaveHouse’s default action is starting the server, that action holds a lot of responsibility: it binds a port, opens a [ClickHouse](/managed-clickhouse) connection, and starts consuming streams. If we don’t properly recognize our CLI arguments and resort to “boot up WaveHouse,” then that could cause a second instance of WaveHouse to be initialized, causing all sorts of downstream issues. So whatever we decide has to make the default behavior a safe one, not something that could become problematic down the line. ## What makes a CLI library useful So, what makes a CLI library actually useful? Obviously, it can’t just be a “flag parsing library.” There are three main tasks that it needs to accomplish: - **Routing:** mapping WaveHouse subcommands to functions - **Parsing:** turning flags and positional arguments into typed values with error checking - **Help:** displaying helpful text for the user and keeping it in sync with existing flags The current implementation in WaveHouse splits these tasks across three different places: the switch statement does the routing, the FlagSet does the parsing, and the help text is something I hand typed as an output based on the “help” argument. Every CLI library bundles these three jobs differently, each for a specific reason. What are the options for building a CLI layer for this binary? ## Option 1: Routing switch plus stdlib FlagSets The first option, as discussed, is the manual switch we have for routing and the FlagSets we use for parsing. They’re two separate pieces of code doing two separate jobs, but they only make sense together. The switch is straightforward, readable, dependency-free, and the default case is safe by construction. This can also scale without nesting. But when two subcommands need to share a flag, we might need to copy the definition or create a new abstraction layer, and that abstraction is something we probably don’t want to write and maintain. The parsing side is the standard library’s `flag` package with one FlagSet per subcommand. This is separate from the routing stuff. The switch is manual and written by hand, but the parsing is a real parser shipped with Go. We get typed values, a help menu per subcommand, and "flag provided but not defined" errors on typos, without writing any of that ourselves. What we don’t get is any idea of what the subcommands actually entail (the switch provides that). We also miss out on short flag aliases and grouped flags. There’s also no automatic main help menu. I had to type that string by hand in the main file. There is one important thing to remember. The parser stops looking for flags as soon as it hits a regular word. You need to put all your flags before any positional arguments. Putting the `--strict` flag before the directory path works perfectly. On the other hand, putting the `--strict` flag after the path will fail because the program reads it as just another argument. ## Option 2: Cobra Cobra is a CLI library commonly used by Go developers. Cobra provides nested subcommands, so `wavehouse settings validate` is just another `AddCommand` call. We can add persistent flags, so a `--settings-dir` defined once on the root command works on every subcommand under it instead of being copied into each FlagSet. Cobra also generates shell completion and docs from the command tree, which is something Kong needs a separate package to do (more on Kong shortly). Here is what our validate subcommand would look like with Cobra: ```go var validateCmd = &cobra.Command{ Use: "validate [dir]", Short: "Validate a settings directory without starting the server", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { dir := os.Getenv("WH_SETTINGS_DIR") if len(args) == 1 { dir = args[0] } return validate(dir) }, } func init() { rootCmd.AddCommand(validateCmd) } ``` The cost of using Cobra is twofold: adding a branch to the dependency tree, and the way the command tree gets built. Each command is a package-level variable in its own file, and an `init()` function registers it with the root at startup. There also isn’t a straightforward way to read the full list of commands, except running grep for `AddCommand`. That part in particular is obviously less favorable than our switch, where every subcommand is a case in one block. When considering our safety rule, I initially thought Cobra would fail it. I had read that a root command with a Run function treats an unrecognized first argument as a positional and runs anyway, which for us means a typo starts the server. In Cobra, with a root command that has subcommands, `wavehouse validat` returns `unknown command "validat" for "wavehouse"` and even suggests `validate`. The root never runs. The rule here is that a root command with subcommands accepts no positional arguments at all, so the safe behavior is the default for our shape of binary. ## Option 3: Kong Kong is a declarative library, so the command tree is a struct. Kong also generates the `--help` output from the struct definition itself, so there’s no usage string to keep in sync. ```go type CLI struct { Validate struct { Dir string `arg:"" optional:"" env:"WH_SETTINGS_DIR" help:"Settings directory."` } `cmd:"" help:"Validate a settings directory without starting the server."` Serve struct{} `cmd:"" default:"1" help:"Start the server."` // bootstrap and health would follow the same pattern } func main() { var cli CLI ctx := kong.Parse(&cli) os.Exit(run(ctx)) } ``` Everything that Kong needs to use lives in struct tags: the backtick strings after each field. This is similar to the `encoding/json` package’s `json:"name"`. Go does nothing with the tag except store it as metadata on the field and Kong reads it at runtime. In the code block above, `arg:""` marks Dir as a positional argument, `optional:""` says it can be omitted, `env:"WH_SETTINGS_DIR"` gives Kong the fallback that our validate function currently does by hand with `os.Getenv`, and `help:"..."` reads the text for the generated help menu. By using Kong, there would be no global state, unlike Cobra, where the commands are package level variables that `init()` functions register at startup. In Kong, the entire command tree is a single struct type, which means you can declare an instance of it basically anywhere, including the inside of a test function, and parse fake arguments against it without touching anything global or having to run startup code. A downside to how you define the command tree is that a compiler cannot check whether or not the struct tag strings are spelled correctly. The compiler will see `arg:"" optional:""` as a string literal, so a typo in that would compile with nothing flagged until runtime. Our safety rule has an interesting catch here. Running the bare program needs to start the server. Kong treats every action as a command, so we tag serve with `default:"1"` to make it the default. This raises the fallthrough question again. If a user types `validat` does Kong throw an error or does it run the server and pass the typo as an argument? From testing this, I found that running with no arguments starts the server. Typing the typo returns an error asking if you meant `validate`. This matches the behavior of Cobra for the exact same reason. The server command refuses extra arguments so the typo gets caught safely. ## Two costs that apply to any library Now that we've considered some CLI layer options, I think there's additional important context for two more contstraints. The first is that `govulncheck` runs in our pre-commit hook, so every module in our dependency graph is something whose version we eventually have to bump, and the timing of that is somewhat out of our control. Adding in a CLI library obviously makes that a slightly larger headache. Second, the CLI library runs before any of our code, which means every time our binary is spun up, that library sits in the path every time. That’s extra code sitting between our code and the user. ## The decision With all of this in mind, my decision rested on a single assessment: whether the switch I had implemented was reasonably scalable. Fortunately, there's a pretty clear indicator for when changes need to be made: nested subcommands and/or shared persistent flags. How much we value shell completion also plays a part in the decision, but that's more of a quality of life distinction than pure functionality. Something like `wavehouse settings validate` is a totally valid shape that our CLI layer could take, but a simple switch won’t nest it nicely. The moment certain arguments need to work on three different subcommands, copying FlagSet definitions obviously isn't ideal. And one day, hand writing a completion script might be the final straw in someone's development session. However, none of these are required of us, nor being requested yet. So, **my simple switch statement stays**. But, when this does become something we need to expand upon, my vote is Kong. In terms of safety, both Cobra and Kong are great alternatives to what I have implemented now. However, I think Kong is a better fit for the shape of our code. WaveHouse prefers configuration that us developers can easily inspect. Our settings directory, for example, gets validated and snapshotted, not changed and configured at runtime, and a command tree that is a struct value fits that same design better than a tree assembled by a bunch of calls to `init()` and the side effects that come with it. Cobra would still work with correct behavior though, so this is driven more by readability/maintainability than functionality. I would just want the command list to live in one place instead of being spread out throughout our codebase. This debate obviously begs the question: Are changes in subcommands coming to WaveHouse? I won't give away *too* much, but you can probably figure it out if you keep an eye (or a star) on the [GitHub repo](https://github.com/Wave-RF/WaveHouse). ## Our blogs can become outdated quickly due to changes in software Everything I've shown here is a snapshot of `main.go` as it stands today, and the CLI is one of the parts of WaveHouse that is actively being worked on right now. The subcommand surface is in active development. When the switch I've defended here does get outgrown, it'll happen the way I described with nested subcommands, shared flags, and the introduction of some CLI library. So please treat this post as the reasoning, not the reference. --- # The WaveHouse Origin Story > Or, how some engineering undergrads 2,000+ miles from Silicon Valley accidentally made a database management system. _2026-08-24 · Jack Woods_ *No generative AI was used at any point during the writing of this blog post. Written and edited by humans in Michigan.* When I decided to attend the University of Michigan College of Engineering in early 2022, I seriously thought that I’d be a *rocket scientist* by this point. My plan was to study aerospace engineering then go on to work for one of the new space players, like Rocket Lab, SpaceX, Relativity etc. I was excited by the competitive landscape and the challenges yet to be solved; I honestly thought I had it all figured out. Things went in a different direction once I met Eric. What follows is the story of WaveHouse, an open source project from Wave RF, from the perspective of… me! Jack Woods, co-founder and CEO of Wave RF. But to understand how we got here, and where we’re going, start at the beginning: 2023. ![Jack giving a thumbs up next to Eric, who is eating a sandwich, outside on a sunny day](https://wavehouse.cloud/_astro/wavehouse-origin-story-1.DkAWn3ss_wTNNK.webp) *Me (left) and Eric (right, eating sandwich), Apr. 2024* ## Part 1: The Beginning (Jan. - Aug. 2023) Eric and I met when he was my lab instructor in my first “real engineering” class during my second semester. We had lots of conversations about open-source software, preferred embedded systems architectures, and technology’s general place in society. We grew a lot closer over the summer after that semester, working together to build a custom tracking system for student-launched weather balloons. The division of labor was simple: Eric did the software, and I did the hardware. While Eric and I both officially had the job title of “Research Assistant”, we really spent that summer of 2023 essentially doing product development. We were provided a lab in the basement of the Climate & Space Sciences Research Building (which quickly filled with prototypes, DigiKey orders, and multimeters) where the two of us worked together to make a system that met all our requirements: able to accurately report location from as high as the edge of space, withstand temperatures down to -30°C, and have 3+ hours of battery life. Most days it felt more like a startup environment than a research lab (this may be foreshadowing). ![A bare green motherboard PCB silkscreened “Balloon Tracker Motherboard”](https://wavehouse.cloud/_astro/wavehouse-origin-story-2.BVEvdJZ0_Z14RRoY.webp) *An unpopulated motherboard PCB for our trackers, Aug. 2023.* *This gives me the ick now… there’s SO many things I’d change.* The project wrapped up as classes started again that fall. One day shortly after classes had started, Eric and I were back down in the basement, just yapping about classes, our lab sections (I’d been hired as a lab instructor to teach alongside Eric), and Michigan football, when Eric shared an idea with me that he’d been mulling over: *what if the low-power and long-range radio tech we’d used in the weather balloons could be repurposed to text during football games at the Big House?* ## Part 2: The Birth of Towerless Texting (Aug. 2023 - Feb. 2024) Like Eric, I recognized the problem, potential applicability of our background, and commercial potential– so I was sold, immediately. For the uninitiated: Michigan Stadium (better known as the Big House) has TERRIBLE cell service. The nearby telecomm infrastructure (or lack thereof) is consistently overloaded by the 100,000+ people in attendance. If you lose your group, want to send a picture to mom and dad, or otherwise need your phone to be Internet-connected: good luck. Eric mentioned that he was taking an entrepreneurship class that semester, and that he could use the project for the class (this becomes important later). I told him I’d love to be involved, and that I could provide any hardware development support he needed. Throughout that semester, Eric funded development himself, and many afternoons were spent refining prototypes and designs. Early on, development was slow. We were underequipped, underfunded, and trying to outsmart billion-dollar telecommunications companies using tiny cheap radios. But, things started looking up in February of 2024 when Eric told me that a professor of his from last semester (remember that entrepreneurship class?) had offered to give him a loan to really pursue this idea. It wasn’t a *ton* of money (though it felt like it was at the time) but regardless, now we were cooking with gas. ## Part 3: The Birth of Wave RF (March 2024 - June 2025) Knowing we had to incorporate, we eventually landed on the name Wave RF for this new venture, and WaveRF, Corp. was incorporated at the end of March 2024– a couple of weeks before my 20th birthday. Recognizing that we couldn’t keep working out of Eric’s cramped apartment, we began renting office space in July. Suddenly it felt real. We had business cards, branded shirts, and pitch meetings. Everyone we pitched early on came back and said “not yet”, which is how investors say no to you politely while leaving the door open for themselves down the road. Nevertheless, development continued. An underwhelming alpha test in the fall of 2024 was a tough setback (we learned a great lesson on the importance of battery undervoltage protection!) but we continued onward, watching the prototype version number slowly climb up through the 10’s and into the 20’s. By mid-2025, we were running on fumes. The professor’s money was almost gone and we had little to show for it. Eric and I faced the hard reality that if we didn’t make something happen by the end of the summer, we’d have to pack it up and go home. I’m not joking when I say that the very next day after Eric and I sat down and agreed that this summer was make or break, we got an email from [1517 Fund](https://www.1517fund.com/). We’d applied to their Flux Capacitor program earlier that spring, and got invited to interview with them, which had gone fairly well. **That email said they’d like to offer us a $100,000 investment to pursue this.** There are three things I will never forget about this deal: the email notification popping up on my laptop, signing the contract, and **just how close we cut it.** **When their check cleared, we had $187 left in the company account.** ## Part 4: The Evolution of Wave (July 2025 - Present) Things didn’t remain sunshine and rainbows, though. Right as we prepared to order our first production run of the device we’d grown to call the Wave Clip (a keychain that lets you text over radio waves) the federal government put tariffs on, like, everything. Our costs jumped 30-40%, nobody knew whether the rates would stay still or keep moving, and this overall completely broke the unit economics for Clip. ![A 3D render of the Wave Clip: a blue keychain enclosure with the Wave RF wave mark and a single button](https://wavehouse.cloud/_astro/wavehouse-origin-story-3.BU57-OIt_Lcb34.webp) *Wave Clip Alpha Rendering - Aug. 2024* I’ll be honest, this one sucked. We’d had setbacks before, but at least those felt solvable and in our control to some extent. This was just a nonconsensual macroeconomic roller coaster. Focus floated around for a while, exploring enterprise solutions (where the unit economics still actually made sense), exploring software-only solutions (where the unit economics were fundamentally different), and everything in between. At this point, we’d begun building an IoT solution based on our previous networking/connectivity experience when we realized that we needed [ClickHouse](/managed-clickhouse). And ClickHouse needed a lot of boilerplate around it to be remotely useful – something not realistic for a small team like ours, and what we’d come to realize is a larger problem than we thought. It was at this moment that WaveHouse was born. Realizing this problem was bigger than just us, and that ClickHouse’s DX left a lot to be desired, we decided to build a single application that is deployed alongside ClickHouse and does the heavy lifting on auth, realtime streaming, RBAC and RLS. We decided to call this WaveHouse, and to open source it. Why open source? That’s an Eric question, not a Jack question. Maybe he’ll write about it :) Regardless, that application has now been built. From a DX perspective, (we think) we absolutely hit the mark: the row-level security (RLS) and ability to return ClickHouse data directly from the frontend mean that developers don’t need to concern themselves with spinning up a backend to manage ClickHouse queries requested by the frontend. Our async batching management also means that the ingest path is durable: a server crash or OOM error won’t cause data loss. Since it’s async, it means that WaveHouse will return a 200 as soon as the data hits the ingest path– no waiting for a batch alert or insert. We also built in realtime streaming over SSE, so repeatedly polling the database is unnecessary. When data comes in that matches the stream request, it gets sent immediately – no batching delay included, even though RLS and type validation still apply. WaveHouse is open sourced and initial releases have started rolling out. [WaveHouse Cloud](/waitlist), our managed offering, is well underway and launching very soon. Initial test deployments of WaveHouse Cloud have been incredibly successful. ## Part 5: In Closing (Present - Forever) So yeah, there’s the rundown: the story of how a couple 20-somethings in Michigan set out to text their friends at college football games, using technology we learned about from building weather balloons, and accidentally made a DBMS for one of the most popular analytical databases in the world. And please, believe me when I say that this **WAS** the summarized version. It’s been ~3.5 years since Eric and I met on that first day of class. Our journey has been nonlinear, brutally stressful, and also the wildest, most educational, and most unique experience I’ve ever had. While it feels like we’re far from the beginning of the story at this point, somehow I know that the end remains even further away.