I just ran into this lame issue with Junie. The system cannot find the batch label specified - after_channel_oneshot.
Ok – so how did I get this? It’s super simple. I tried installing it via the command they give on their website: https://junie.jetbrains.com/
This is the command they give: powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (irm 'https://junie.jetbrains.com/install.ps1')" After running that command, you restart powershell and junie and it works, normally. This time it wasn’t. I went through a load of debugging steps. Deleting caches, deleting other bats, etc… But the one thing that actually helped came from this StackOverflow post. The Line endings were wrong.
So – how to fix? I downloaded the install.ps1 file directly and converted the line endings to CRLF. I opened it in Notepad++ and used Edit > EOL Conversion > Windows (CR LF)
Then I ran powershell -ExecutionPolicy Bypass -File .\install.ps1 directly. BAM! It works. No more mad mad.
I’ve been working with Kilo CLI for the last day. So, this is first impressions. This is coming from working with Codex CLI for a few months. The following post comes from this experience. In this case I’m using GPT-5.5 medium in both Kilo and Codex.
The Kilo AI CLI has some cool features. I really appreciate the ability to connect with your existing provider. I like the auto-model routing. The interface is pretty cool, with a lot of themes to choose from. There is a persistent status section in the CLI that shows usage, context available, tokens used, modified files. It’s really cool.
However, I’ve consistently run into issues since attempting to use Kilo. And it’s not with the interface or the functionality of the software. It’s with the underlying tooling. Something about Kilo causes the LLM to do things that I don’t want it to do. Here’s an excerpt from my AGENTS.md file.
When the user pastes review feedback, follow the Review Feedback section below. Treat the feedback as a claim to verify, explain the conclusion, recommend the smallest correct fix, and ask before implementing unless the user explicitly asks for changes.
...
## Review Feedback
When addressing merge request or code review feedback, treat each comment as a claim to verify, not as an instruction to apply automatically.
- First confirm whether the reported problem is real by reading the relevant code paths and, when practical, reproducing or reasoning through the behavior.
- Validate suggested solutions before implementing them; they may be incomplete, too broad, or aimed at the wrong boundary.
- If the issue is valid, choose the smallest correct fix that changes the fewest lines and preserves existing intended behavior.
- If the issue is not valid, explain why with concrete code references or behavior.
- If a minimal fix could hide an inconsistent state, distinguish the legitimate case from the suspicious case and handle each explicitly.
That’s pretty clear about what I expect. My expectation is no changes unless it’s verified with me. Or unless I tell the agent to explicitly fix it. Over the last day I’ve given feedback to the agent and it continues to ignore my instructions, opting instead to make a change without verifying it with me. That’s frustrating.
Kilo Modes
Kilo comes with several modes out of the box. There’s a Code mode, a Plan mode, an Ask mode, a Debug mode, and an Orchestrator mode. Now, this frustration could be my fault for using the tool wrong. I started in “Code mode”. Perhaps, code mode, means that Kilo is going to strongly tell the LLM to write code, even if it contradicts my instructions. It could be my fault for not starting in ASK mode and then flipping to CODE mode. But… seriously. I’m not going to sit here switching modes all day when I expect the tool to be smart enough to follow instructions. If the tool is in code mode, and the instructions are “ask before coding” then the tool should ask. The mode should be inferred from the prompt. If the prompt is a question, then assume an answer is wanted. If the prompt is, fix this issue, then assume that a combination of debug+code is wanted. If the prompt is, implement this feature, then assume orchestrator+code is likely wanted.
Maybe that’s just me. But switching between modes seems like busy work for me.
Kilo Tooling
I have RTK set up on my machine and integrated into my AI agents. The tool exists as rtk and is callable by the AI agents. However, the code I was writing was in php and I don’t have php installed on my system. I do have it running in a container running on my system though. I have explicit instructions in my AGENTS.md file telling the Agent to look at local machine notes. My local machine notes tell the Agent all about how this current system uses Fedora and Podman for containers.
Today, Kilo failed hard on a few things: – It did not use rtk. It attempted to use rtk php and when that failed it assumed rtk did not exist and didn’t use it anymore. – It did not read my local notes. And because it did not read my local notes (despite being told to in the AGENTS file) it failed to validate my code using php – It tried to use docker multiple times even though the local notes tell it to use podman
Working Verdict
I really like the concept of Kilo. Super cool interface, super cool themes, super cool status window, an auto-model selector. Kilo has a lot of good stuff going for it.
I’ve worked with Kilo and attempted to use it. It’s been an incredibly frustrating experience. Kilo is not reliable and it doesn’t listen.
Despite all the cool, and the hype, when the rubber meets the road Kilo is not up to snuff. Kilo is not up to snuff because Kilo ignores explicit directions.
My plan is to use Pi.dev. I’ve heard that it will work with the Kilo gateway. I probably won’t come back to Kilo, but who knows, they might update the tool to be more reliable. If they do, I’ll try it again.
It’s one of those places that I used to spend a lot of time on. But then the community got all pretentious and it became more important to users to show you all the ways your question had already been answered instead of just answer it.
About the time I started really disliking StackOverflow, ChatGPT came around and… well it doesn’t yell at me for my questions.
So, one of the most annoying things IN MY LIFE has been when JetBrains started adding all of this random AI Assistant autocompletes to their IDE’s. I know I’m not alone, because there are even tickets like this one, How to Shut Off All this AI Crap?.
It’s not that I’m anti-AI – I’m anti-Intrusion. When I’m driving the car, I get to drive the car, not the AI Assistant. Unfortunately, the way JetBrains is adding AI into it’s editor feels very intrusive. And, also unfortunately, it’s a slog to go through all of the IDE settings to try and find every single little thing that needs to be turned off.
Luckily, you don’t need to! JetBrains has added some files that will allow you to selectively use AI tools. My favorite is dropping a .noai file in your project root. It’s easy to do, navigate to your project root in Powershell and run touch .noai. That’s it, all you need is an empty file to disable all the AI stuff in PHPStorm.
Now you can get back to PHPStorm Classic mode. LFG? Molten Core? … oops wrong classic mode.
But what about Junie?
That’s a valid question. Like I said, I’m not anti-AI. I actually like the coding agents, I’ve found them extremely helpful in certain circumstances. So, I wondered, will .noai disable all coding agents? Nope! It won’t. As of this writing .noai will disable the AI Assistant features in the IDE – but you can still use the Junie agent window. I don’t know if that’s an oversight or not, I actually recently heard that the Junie agent window is going away as they consolidate underneath the AI Assistant chat window.
The Better Junie Option (imo)
The better option, in my opinion, is to just use the Junie CLI. It’s currently in beta, and appears very usable from my testing. It’s integrated with your current JetBrains AI pricing model, so if you pay to use Junie within your IDE, then you are paying to use the CLI tool as well. I’ve found that I can open my own custom terminal, or use the built in IDE terminal, and open Junie via CLI. This gives me the best of both worlds, a powerful IDE and a powerful coding agent. I can use both when I want.
Not Quite .noai
Despite .noai working in most circumstances, I’m noticing little bits of AI crop back up. For example, inline Code Completion. I’m wanting classic intellisense, but JetBrains is giving me inline completion using cloud and local models. I had expected this to not happen, and indeed thought it wasn’t happening. But today, as I’m coding, I noticed phpstorm giving me ghosted AI completion hints. So, I navigated to phpstorm settings Editor > General > Code Completion > Inline and unchecked the Enable inline completion using language models: option.
I just experienced an issue which took me a day to figure out. So, as per normal, I’m going to document it here so that in the future I don’t have to bother looking it up!
My problem: every time I try to commit using git I am asked for my SSH key passphrase. However, I’ve ensured the SSH agent is running. I can pull from the remote, push to the remote, and do anything with the remote repository without needing to insert my SSH key multiple times. However, when I try to commit via git, I’m asked for my passphrase on every commit. Why is this a problem? Because when I rebase a 150+ branch of commits I’m having to enter my passphrase 150 times consecutively. That’s unsustainable.
Still, even armed with Christopher’s information, I couldn’t figure out how to fix the problem I as running into.
Since this post is meant to help guide me in setting this up from scratch (AGAIN) I’m going to go through all the relevant steps. But if you are just looking for the solution to the problem then skip to here.
Setup
Everyone’s setup is a bit different, but I’m going to document the relevant portions of mine.
Environment
Clean Install of Windows 11
Git Note: When installing I select the “Use Git and optional Unix tools from the Command Prompt”
After my environment is setup, I set up SSH. This involved creating a new key, adding it to the SSH Agent, and making sure the agent was running. I run all these commands from an instance of Powershell Core (installed above).
Adding the key to the agent is simple enough. You just need to run a command and give it the location of the private SSH key you generated in the step above. In my case that’s as simple as:
Now I would either typically restart my computer, or close the current PowerShell Core window and open a new one.
Adding the SSH Key to GitHub
If you want to sign commits with GitHub then you need to upload your SSH key 2wice (that’s a clever way of writing twice). One upload for your “Authentication Key” which will be for access to the repo. The second upload for your Signing Key. You can do both at https://github.com/settings/keys just click “Add Key” in the SSH Keys section and upload one for Authentication and then click “Add Key” again and upload one for Signing.
Signing Git Commits
Once again, referring to Christopher’s post. I do the following, making sure to switch out the path to my pub SSH key:
Ok. Now the problem. You’ve successfully connected to Github and cloned your repo. Now you start making commits and find that you have to insert your SSH key passphrase over and over, despite the SSH agent running.
It took me a long time to figure out, but the problem is likely that you have two versions of SSH on your machine. The one that comes with Windows by default, and the one that came with Git for Windows when it was installed.
To solve this problem, tell Git For Windows to “Use external OpenSSH” when installing Git. The following comes from this answer on Stack Overflow by Ajedi32.
If you used the bundled OpenSSH installation, git will default to that and will not use any keys imported into Windows’ native ssh-agent service. You need to select “Use external OpenSSH” instead when prompted.
If you did not make this selection when installing, you should be able to fix that by just running the installer again.
Previous Versions of this article said the following. This is no longer what I recommend.
You’ll remember we selected the “Use Git and optional Unix tools from the Command Prompt” option. This option will add the referenced Git and Unix tools to your systems Path. The SSH Agent that is registered and used for Authentication is the one that comes installed with windows. The one that Git is using for signing, is the one that comes with git.
The order of the PATH variables will determine which version of the ssh-agent is used. The first version encountered will be the one that windows uses. So, to solve this problem, make sure the C:\Program Files\Git\usr\bin is above the %SYSTEMROOT%\System32\OpenSSH\ in your system path.
I am currently looking into alternative forms of user authorization and authentication. Among the solutions I am looking into is Clerk. It’s pretty sweet and has a lot of cool features baked in. (Although the MFA support is a premium add-on and they aren’t super upfront about that).
One of the issues I ran into while implementing Clerk was a redirect loop. I set my home page within the Clerk Dashboard and when I reloaded my app, boom REDIRECTION FOR DAYS. Clerk was continuing to reload the home page for all eternity.
So, I added an onbeforeunload event into the page with a debugger call inside of it. This paused the page in the inspector before it reloaded and allowed me to actually see what was going on.
It turns out that Clerk was outputting an error message into the console. This error message is pictured below:
The <SignUp/> and <SignIn/> components cannot render when a user is already signed in, unless the application allows multiple sessions. Since a user is signed in and this application only allows a single session, Clerk is redirecting to the Home URL instead. (This notice only appears in development)
? Clerk
Well – ok then. Clerk is redirecting to the Home URL (which is the one it’s already on) and causing a permanent redirect loop. It seems like this would be handled better by simply _not_ loading the SignIn or SignUp components should the conditions for their existence fail.
Hopefully this helps you out! You might consider making your home page and your sign in pages different pages, or conditionally load those components, so that Clerk can be happy and not mess things up.
That’s a good question. You might ask this when you are implementing a new project and trying to figure out where to store your secret configuration values.
Before getting into the difference, let’s state the similarities:
Both allow storage of environment specific configuration values and secrets from outside of your codebase.
Both allow retrieval of environment specific configuration values and secrets from outside your codebase.
Both files use a key value pair type format.
Both allow comments within the files.
So what about the differences?
The names are different .ini vs .env
The method of storing the data is different.
The method of retrieving the data is different.
The syntax is different.
That probably doesn’t answer your question though. You likely aren’t interested as much in what the differences are as you are in why you would use one over the other.
Why use .env instead of .ini or .ini instead of .env?
This is likely what you are wanting to know, why would you use one over the other. So let’s list some pro’s and cons of each format to help make the decision.
.env Pros
language-agnostic
allows referencing other .env values as variables
libraries like phpdotenv provide robust functionality
Let’s expand a little on the language-agnostic pro above.
First Scenario. You are coming to PHP from another environment, like Ruby, you are probably wondering where to put your secrets and configuration values for your code. A .env file just makes sense, these are supported in Ruby so there must be a way to add them in PHP. Voila! There is a package that supports .env files that you can easily include in your PHP code and you don’t have to think anymore about it. It probably doesn’t even occur to you to use the build in .ini support.
Second Scenario. You are using both server side JS, like Node, and PHP. You want to share configuration values between the two systems. Both support .env files allowing you to easily share your secrets between both languages.
.ini Pros
built-in PHP Support
allows grouping of values via sections
supports typed values via INI_SCANNER_TYPED
allows interpolating other config values and environment variables
.env Cons
requires third party library and composer to work
features provided change based on library used for loading
*some libraries load configuration secrets into globally accessible variables like $_SERVER or $_ENV which will could expose your secrets to code you don’t intend to
.ini Cons
requires familiarity with PHP
Which one should I use?
I’m going to give you the answer you don’t want to hear. That’s up to you. It really depends on the needs of your environment and your program.
As far as my personal preferences go. I don’t like including unnecessary dependencies in my codebase. Therefore, if I’m using PHP to develop my app, and I have no need to share my config secrets with other languages, then I would use an .ini file and the built in support for those that PHP provides.
Ok, let’s cut to the chase. Everyone knows that converting a JavaScript Map to JSON does not work out of the box. By default, the JSON.stringify method will return a {} when converting a Map. It’s super helpful, because it returns an empty object, which is usually precisely what we don’t want. That’s a wee bit frustrating!
How Not to Serialize a Map to JSON
The internet has provided us with the silver bullet, though, right? Object.entries is great and can do all things, right? WRONG. That is wrong and you are wrong if you think that it’s right. You see what I’m getting at?
The existing advice is to use Object.fromEntries and Object.entries in tandem to make it easy to convert a map to and from JSON. The code below shows you this method in all it’s glory.
// ### inspired code below
const mapToSerialize = new Map([[1, 'first key']])
const serializedMap = JSON.stringify(Object.fromEntries(mapToSerialize ))
// now deserialize
const deserializedMap = new Map(Object.entries(JSON.parse(serializedMap)))
Isn’t the code above beautiful? Doesn’t it just wonderfully handle our serialization in the best of ways? No! It doesn’t. Let’s compare the original map to the deserialized map and see how amazing the code works.
The original map looks like this when logged to the console Map(1) {1 => 'first key'}. The deserialized map looks like this when logged to the console: Map(1) {'1' => 'first key'}. Did you spot the difference?
Just to make things clear, let’s try to delete the keyed value out of our Map.
Hey look, deleting that value totally didn’t work
So really, in the end, our serialization using the currently advised method totally works. We serialize our map, deserialize it, and then can’t use it properly. Just as we expected.
NO. It doesn’t work correctly. The difference is that the original map uses an integer key, and the deserialized map uses a string key. When we attempt to delete the value out of the deserialized map, using the key, it fails because the type doesn’t match.
How to Serialize a Map to JSON
I am proposing a different way to serialize a map to JSON.
Create a new array from the existing map
Serialize the array to JSON
Create a new map from the deserialized JSON
The code I propose looks like this. You might not want to keep the logging at the end in your own implementations.
/// ### ugly code below
const mapToSerialize = new Map([[1, 'first key']])
// convert the map to JSON
const arrayToSerialize = []
mapToSerialize.forEach((value, key) => arrayToSerialize.push([key, value]))
const serializedMap = JSON.stringify(arrayToSerialize)
// convert the JSON back to a map
const deserializedMap = new Map(JSON.parse(serializedMap))
// log to console for inspection
console.log(mapToSerialize)
console.log(deserializedMap)
This code correctly works to serialize and deserialize a map to/from JSON.
Look at that, both maps match
In Conclusion
Serializing a Map to and from JSON isn’t as simple as it looks on the outside. Especially if from the outside it looks like it would be super simple. The Object.entries silver bullet only works for Maps with string keys, and attempting to use it for Maps with integer keys will end up with you hating your life. You probably will start listening to Barry Manilow constantly. You might even start eating Quinoa. I’m sure it happens all of the time due to Map serialization woes.
Anyways, if you prefer to not eat Quinoa, then go ahead and convert your Maps to and from JSON the way I suggested above.
I just ran into a problem and I wanted to document it for myself and for anyone else who might have issues. First I describe the problem, then I give the solution. Scroll down if you’re looking for the solution.
The Problem
After posting with JavaScript fetch I did not see the “body” arguments come through on the server. The method of the fetch was set to POST and the body included was an instance of FormData. According to the documentation on MDN, everything should’ve worked. So why wasn’t it working?
The Basic Client Side Code
const body = new FormData(myForm)
// assume myForm.action = "https://example.com/ajax/post"
const response = await fetch(myForm.action, {
method: "post",
body,
})
The Basic Server Side Code
<?php
// file: index.php within the ajax/post directory
// don't bother processing the post if there is none
if(empty($_POST)){
exit;
}
// ... processing code below
I spent some time debugging and without a doubt, every POST request to the index.php file did not have the $_POST array filled out. The POST array was empty as well as the REQUEST array, even the oft-touted file_get_contents('php://input') came up empty.
The Solution
You aren’t going to like it. I don’t like it. The solution to this problem is so annoying that you’ll just facepalm like Picard.
Add a slash to the end of the url you are posting to.
The problem url is: https://example.com/ajax/post The working url is: https://example.com/ajax/post/
Currently, when this url is posted to, the server responds with a 301 Redirect before the index.php file is hit. But why? The problem is that you do not have a trailing slash in your url. That’s it. You are posting to an index.php file within a directory, but your url does not have a trailing slash. So your server helpfully redirects you to a url with a trailing slash, and you lose your posted information along the way.
Yep, that’s it. Add a trailing slash and you’ll see your body come through when debugging.
As you might know, I’ve set up a RocketChat server recently on Digital Ocean. So far it’s been working great. An update every once and a while is all it needs.
However, yesterday, I attempted an update that failed. From then on every attempted update resulted in “RocketChat server not running. Cancelling”. This was very frutrating.
First, a few commands to try that might help:
systemctl restart rocketchat.service – This will start your RocketChat server in case it is stopped.
systemctl status rocketchat.service – Use this command to check the results of the previous command. Typically this will report that the service is “Active” if the previous command was successful.
In my case, the second command resulted in a “failed” state. The command itself gave me some information as to what the failure was, but not a lot of context as to what caused the failure. However, it did show me the process that it attempted to run. It said, ExecStart=/opt/nvm/versions/node/v14.19.3/bin/node /opt/Rocket.Chat/main.js (code=exited, status=1/FAILURE).
Alright! We’re getting somewhere. With that I was able to figure out what command failed and where that command was run. I navigated directly to the /opt/Rocket.Chat directory which was where the failure was occurring. From here I ran node main.js. The results of this command were much more helpful. They told me this, Error: Cannot find module '@meteorjs/reify/lib/runtime'. That looks like an issue with npm dependencies.
So, I poked around the Rocket.Chat directory structure and looked for dependencies for the Rocket.Chat server. I found what I was looking for in the /opt/Rocket.Chat/programs/server directory.
From this directory I ran two commands
npm install
npm ci
Afterwards I attempted to start the RocketChat server again using the systemctl restart rocketchat.service command. I checked it with systemctl status rocketchat.service and found that it was working now! RocketChat was back to running normally. The problem with “RocketChat server not running. Cancelling” was gone!