<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Slate</title>
    <description>The latest articles on DEV Community by Slate (@slate_co_il).</description>
    <link>https://dev.to/slate_co_il</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4047641%2F7d5436cb-4a8f-4c26-bea4-c249ddcc1035.png</url>
      <title>DEV Community: Slate</title>
      <link>https://dev.to/slate_co_il</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/slate_co_il"/>
    <language>en</language>
    <item>
      <title>Jarvis Talking Assistant for Claude Code</title>
      <dc:creator>Slate</dc:creator>
      <pubDate>Fri, 14 Aug 2026 09:46:04 +0000</pubDate>
      <link>https://dev.to/slate_co_il/jarvis-talking-assistant-for-claude-code-101o</link>
      <guid>https://dev.to/slate_co_il/jarvis-talking-assistant-for-claude-code-101o</guid>
      <description>&lt;p&gt;I got tired of typing at my AI assistant. So I gave it a voice, a microphone, and a glowing blue orb to live in. The whole thing is two files and three dependencies. I called it JARVIS, because of course I did.&lt;/p&gt;

&lt;p&gt;Here is what it does. You open a web page. You hold down the space bar and talk. The orb in the middle of the screen listens, and one of its rings pulses in time with your voice so you can see it hearing you. You let go, and it thinks. Then it answers out loud, in a British accent, while the text of what it is saying scrolls up the page.&lt;/p&gt;

&lt;p&gt;The part I care about most is that it starts talking before it has finished thinking. Most voice assistants wait for the entire answer to be written, then read it to you. That pause is short, but you feel it, and it makes the thing feel like a machine reading a card. Mine watches the words arrive and speaks each sentence the moment that sentence is complete. By the time it is working out its second thought, you are already hearing the first. It feels less like waiting for a reply and more like someone talking.&lt;/p&gt;

&lt;p&gt;It is not just a chatbot with a speaker bolted on. It can actually do things — read your files, edit them, run commands, search the web. When it does, a small gold tag appears in the transcript telling you which tool it used and on what, so you are never guessing what it just touched. It also inherits whatever tools you have already set up for yourself, rather than living in its own little sandbox.&lt;/p&gt;

&lt;p&gt;The hardest problem turned out not to be the voice or the microphone. It was that everything an AI writes is designed to be read, not heard. Bullet points, headings, code blocks, file paths, numbers like 8765 — all of that is fine on a screen and awful out loud. A speech synthesizer will happily read you a markdown asterisk. So I told the assistant, up front, that its words were going to be spoken: keep it short, keep it conversational, no lists, no formatting, say numbers as words, and do not narrate every step of what you are doing. Fixing it at the source worked far better than trying to strip the formatting out afterwards.&lt;/p&gt;

&lt;p&gt;The orb is the other thing I would not cut. It has no buttons and no labels, but you always know where you are: calm blue when it is idle, green while it is listening, a fast nervous pulse while it is thinking, gold while it is speaking. Four colours doing the job of an entire interface.&lt;/p&gt;

&lt;p&gt;One honest warning. I set it to make file edits without stopping to ask permission, because being interrupted by a confirmation dialog defeats the point of talking to it hands-free. That is a real trade-off, not a detail. It is fine for a toy on my own machine. I would think hard before pointing it at anything I could not afford to lose.&lt;/p&gt;

</description>
      <category>jarvis</category>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Accounting AI features that makes the diffrence</title>
      <dc:creator>Slate</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:52:40 +0000</pubDate>
      <link>https://dev.to/slate_co_il/accounting-ai-features-215b</link>
      <guid>https://dev.to/slate_co_il/accounting-ai-features-215b</guid>
      <description>&lt;p&gt;A site at  that takes an unusual position for accounting content: it explains the rule first and names the software second. The subject is AI in bookkeeping, and the treatment is more skeptical than most vendor blogs allow themselves to be.&lt;/p&gt;

&lt;p&gt;The core argument is a split. Some AI features in accounting are real time savings, some are old rules engines with a new label, and a third group should never run without a person watching. Document reading sits in the first group. A model looks at a receipt photo, returns supplier, date, total and VAT amount, and the expense form comes back filled in. In Israel that matters more than elsewhere, because small suppliers still hand out thermal paper that fades inside a year. Scanning at the counter turns a shoebox into a five second task.&lt;/p&gt;

&lt;p&gt;Categorization is the second real win, and the site is honest that it barely needs a model at all. The second time you buy from the same supplier, the account should already be there. The site ships a browser demo of this: type a transaction in plain language, watch it turn into a bookkeeping entry with a confidence score. A keyword table stands in for the model, which is a fair way to show the output shape without pretending to more machinery than the job needs.&lt;/p&gt;

&lt;p&gt;Then the skepticism. Fully automatic bookkeeping gets a slow read of the fine print, because the same 340 shekels at the same supermarket is groceries one week and a client meeting the next, and no model sees the difference from a transaction line. Automatic VAT filing usually means the software prepares numbers and you press submit, which is the right division of labor and a much smaller claim than the advertising. Predictive cash flow with a few dozen invoices of history is arithmetic on your own payment terms wearing a nicer chart.&lt;/p&gt;

&lt;p&gt;The part worth stealing is the design rule the site demands from any vendor: AI produces a suggestion, a human accepts it, and only then does anything get written to the books. Issuing a tax invoice is the example. Once issued it cannot be edited, deleted or renumbered, it belongs to a gapless sequence, and in Israel it may need an allocation number from the Tax Authority before the customer can deduct anything. A feature that writes a fiscal record with nobody looking has chosen its demo over your audit trail.&lt;/p&gt;

&lt;p&gt;Alongside the guides there are two working tools, both free and both running entirely in the browser with no account and no upload: an invoice generator that calculates VAT and prints clean, and the expense categorizer. The site says plainly that these are demos, and that real documents belong in invoicing software built for Israeli rules.&lt;/p&gt;

&lt;p&gt;There is also a ten minute vendor test. Photograph your worst receipt. Check that you can edit every field before saving. Ask the assistant something you already know the answer to. Try to edit an issued invoice, and leave if it lets you. Export your data. The site claims the last one eliminates more vendors than the other four together, and that sounds about right.&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
      &lt;div class="c-embed__body flex items-center justify-between"&gt;
        &lt;a href="https://accounting-ai.tomerdamari.workers.dev/" rel="noopener noreferrer" class="c-link fw-bold flex items-center"&gt;
          &lt;span class="mr-2"&gt;accounting-ai.tomerdamari.workers.dev&lt;/span&gt;
          

        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>productivity</category>
      <category>software</category>
    </item>
    <item>
      <title>Printing documents with a headless browser instead of a PDF library</title>
      <dc:creator>Slate</dc:creator>
      <pubDate>Sat, 01 Aug 2026 08:13:48 +0000</pubDate>
      <link>https://dev.to/slate_co_il/printing-documents-with-a-headless-browser-instead-of-a-pdf-library-hp5</link>
      <guid>https://dev.to/slate_co_il/printing-documents-with-a-headless-browser-instead-of-a-pdf-library-hp5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2nigqekwqkdfv4k3tif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs2nigqekwqkdfv4k3tif.png" alt=" " width="799" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most billing systems reach for a PDF drawing library and end up hand-placing coordinates for every line of every table. Ours prints HTML. The markup that renders the on-screen document preview is the same markup handed to headless Chromium, which prints it to A4. Layout stays in CSS, pagination stays in the browser's fragmentation engine, and the file the customer opens cannot drift from what the issuer saw.&lt;/p&gt;

&lt;p&gt;One document, two builders&lt;br&gt;
An issued document renders only from its frozen snapshot: business details, customer details, VAT rate and logo as they were at issue time, never live settings. The authenticated path builds the HTML in the client, where locale, accent color and the QR code for the verification link already live. The public share link has no session to read those from, so a server-side mirror of the same builder produces byte-comparable markup with server-resolved labels. Both call one render function, so the two paths can't disagree about what a document looks like.&lt;/p&gt;

&lt;p&gt;Everything inlined, nothing fetched&lt;br&gt;
The HTML that reaches Chromium is self-contained. Hebrew fonts are base64 @font-face sources, the business logo is a data URI, the QR image is a data URL. That is not only a packaging convenience. The render input is client-supplied, so the page runs behind request interception that continues data: and about:blank and aborts everything else. Without it, a crafted would execute inside a browser sitting on the server's own network: an SSRF hole with a PDF for an exfiltration channel.&lt;/p&gt;

&lt;p&gt;Two print passes&lt;br&gt;
Page margins are set as real print margins (20mm top and bottom) rather than body padding, because CSS fragmentation applies a block's padding before the first fragment and after the last one only. Padding would leave interior pages flush against the paper edge.&lt;/p&gt;

&lt;p&gt;The signature and QR block should sit at the bottom of its actual last page. Its exact height is not knowable ahead of the render, since text extraction cannot see the QR &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; at all. So the position is found empirically: a binary search over the block's margin-top, eight iterations, each one re-printing the page and inspecting the result. Page count comes from pdf-lib, and the last page's text content from pdf.js, to detect a wasted trailing page. The search converges toward the natural margin from whichever side the first render landed on. The winning margin is left applied to the DOM, and a second print adds the per-page footer through Chromium's own footer template, where page number and total are substituted per page.&lt;/p&gt;

&lt;p&gt;Concurrency and guards&lt;br&gt;
One Puppeteer browser is launched lazily and shared; each request gets a page that is closed in a finally. A three-slot FIFO semaphore caps concurrent renders, handing a freed slot directly to the next waiter so a fresh caller cannot slip past the cap. Imported historical documents carry no snapshot or signature and are rejected server-side, by document id, not just hidden in the UI. The public route is rate-limited per IP, since each hit is a full browser render. Every generated file is logged with its byte size and wall-clock duration.&lt;/p&gt;

&lt;p&gt;Content by &lt;a href="https://www.slate.co.il/" rel="noopener noreferrer"&gt;Slate&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>toISOString().slice(0, 10) is not today's date</title>
      <dc:creator>Slate</dc:creator>
      <pubDate>Fri, 31 Jul 2026 06:52:23 +0000</pubDate>
      <link>https://dev.to/slate_co_il/toisostringslice0-10-is-not-todays-date-3mf5</link>
      <guid>https://dev.to/slate_co_il/toisostringslice0-10-is-not-todays-date-3mf5</guid>
      <description>&lt;p&gt;A user reported that an invoice they issued on the 1st of the month was dated the 31st of the previous month. VAT reports in Israel are filed by calendar month, so this was not cosmetic. The invoice landed in the wrong reporting period.&lt;/p&gt;

&lt;p&gt;The bug was one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;issueDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;toISOString()&lt;/code&gt; returns UTC. Israel is UTC+2 (UTC+3 in summer). Issue a document at 00:30 local time and UTC still says yesterday. The user gets a legal document carrying the wrong date, and nobody notices until an accountant does.&lt;/p&gt;

&lt;p&gt;The fix is to format in the business's own timezone, not the server's and not UTC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;localDateString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Asia/Jerusalem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Intl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en-CA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;timeZone&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// "2026-07-31", en-CA locale gives YYYY-MM-DD directly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same rule on the backend. A Node server deployed in Frankfurt runs on UTC, so &lt;code&gt;new Date().getDate()&lt;/code&gt; there is just as wrong as &lt;code&gt;toISOString()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two lessons that outlived the bug:&lt;/p&gt;

&lt;p&gt;First, a fiscal date is a calendar day, not a timestamp. Store it as a plain &lt;code&gt;YYYY-MM-DD&lt;/code&gt; string, not a &lt;code&gt;Date&lt;/code&gt;. The moment you store midnight-UTC datetimes for date-only facts, every serialization boundary (database driver, JSON, ORM) is a new chance to shift the day. The "when exactly did this happen" question belongs to a separate audit timestamp in full ISO, with the timezone kept.&lt;/p&gt;

&lt;p&gt;Second, decide which timezone owns the date once, and put the helper next to that decision. We centralized it into one &lt;code&gt;localDateString()&lt;/code&gt; util on the client and one &lt;code&gt;jerusalemToday()&lt;/code&gt; on the server, and banned raw &lt;code&gt;toISOString().slice&lt;/code&gt; in review. The bug never came back.&lt;/p&gt;

&lt;p&gt;This came out of building &lt;a href="https://www.slate.co.il/" rel="noopener noreferrer"&gt;Slate&lt;/a&gt;, invoicing software for Israeli businesses, where a document's date decides which VAT period it belongs to. Any app that puts a date on a legal or financial record has this bug waiting if it formats dates through UTC.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>node</category>
      <category>programming</category>
    </item>
    <item>
      <title>Five AI features in an invoicing app, and the rules that keep them from touching the books</title>
      <dc:creator>Slate</dc:creator>
      <pubDate>Sun, 26 Jul 2026 07:32:23 +0000</pubDate>
      <link>https://dev.to/slate_co_il/five-ai-features-in-an-invoicing-app-and-the-rules-that-keep-them-from-touching-the-books-3kh1</link>
      <guid>https://dev.to/slate_co_il/five-ai-features-in-an-invoicing-app-and-the-rules-that-keep-them-from-touching-the-books-3kh1</guid>
      <description>&lt;p&gt;I build Slate, an invoicing and bookkeeping SaaS for Israeli businesses. Angular on the front, Express and Prisma on the back, Postgres underneath. The documents it issues are real fiscal records. Israeli law requires them kept for seven years, numbered without gaps, and never edited after issue.&lt;/p&gt;

&lt;p&gt;That constraint shaped every AI feature in the product. There are five of them today:&lt;/p&gt;

&lt;p&gt;receipt scanning (photo of a receipt, out comes a filled expense form), a chat assistant that answers questions about your own books, a support reply drafter for the admin side, natural language document creation ("quote for Dani, 3 consulting hours at 500"), and column mapping for Excel imports where every accountant's spreadsheet has different headers.&lt;/p&gt;

&lt;p&gt;You can see it here: &lt;a href="https://www.slate.co.il/en/#features" rel="noopener noreferrer"&gt;https://www.slate.co.il/en/#features&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>saas</category>
      <category>software</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
