MoreRSS

site iconThe Practical DeveloperModify

A constructive and inclusive social network for software developers.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of The Practical Developer

Run Your Dev Server Without a .env File

2026-03-05 08:06:09

Every project has one. A .env file sitting in the project root with database passwords, API keys, and secrets of varying sensitivity. You have it in .gitignore. You hope nobody accidentally commits it. You send it to new teammates over Slack because there's no better option. You've probably forgotten it's there half the time.

The .env file is the developer ecosystem's accepted bad practice. Everyone knows it's not great. Nobody has a better answer for local development that doesn't require enterprise infrastructure.

agentsecrets env is that answer.

What It Does

agentsecrets env is a process wrapper. You put it in front of any command. It pulls your secrets from the OS keychain and injects them as environment variables into the process at launch. The process reads from os.environ normally — no changes to your application code, no SDK to install, no integration work. When the process exits, the values are gone. Nothing was written to disk.

# Instead of:
python manage.py runserver

# You run:
agentsecrets env -- python manage.py runserver

That's the entire change to your workflow. Everything inside your application stays identical.

The Setup

# Install
brew install the-17/tap/agentsecrets
# or: npm install -g @the-17/agentsecrets
# or: pip install agentsecrets

# Initialize and store your secrets
agentsecrets init
agentsecrets secrets set DATABASE_URL=postgresql://user:pass@localhost/mydb
agentsecrets secrets set STRIPE_SECRET_KEY=sk_live_51H...
agentsecrets secrets set DJANGO_SECRET_KEY=your-secret-key
agentsecrets secrets set OPENAI_KEY=sk-proj-...

# Or import your existing .env all at once, then delete it
agentsecrets secrets push
rm .env

Values go to the OS keychain — macOS Keychain, Windows Credential Manager, or Linux Secret Service. Not a file. Not an environment variable in your shell profile. The OS keychain requires system-level authentication to access and is not readable by other processes.

Django

Your settings.py doesn't change:

import os

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.environ["DB_NAME"],
        "PASSWORD": os.environ["DB_PASSWORD"],  # injected by agentsecrets env
        "HOST": os.environ["DB_HOST"],
    }
}

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
STRIPE_SECRET_KEY = os.environ["STRIPE_KEY"]

Run your Django commands:

agentsecrets env -- python manage.py runserver
agentsecrets env -- python manage.py migrate
agentsecrets env -- python manage.py shell
agentsecrets env -- celery -A myapp worker --loglevel=info
agentsecrets env -- python manage.py test

Node.js / Next.js

agentsecrets env -- node server.js
agentsecrets env -- npm run dev
agentsecrets env -- npx next dev
agentsecrets env -- npx ts-node src/index.ts
agentsecrets env -- npx prisma migrate dev

Your application reads process.env.STRIPE_KEY exactly as before. The source of the value changed. The interface didn't.

The Makefile Pattern

This is the lowest-friction way to adopt agentsecrets env across an existing project. Add one line to your Makefile:

RUN := agentsecrets env --

dev:
    $(RUN) npm run dev

test:
    $(RUN) npm test

migrate:
    $(RUN) python manage.py migrate

server:
    $(RUN) python manage.py runserver

worker:
    $(RUN) celery -A myapp worker --loglevel=info

Now make dev, make test, make migrate all run with secrets injected from the keychain. You type the same commands you always typed.

One bonus: you can override RUN from the shell to strip injection entirely when debugging:

make dev RUN=        # runs: npm run dev (no injection, for debugging)
make dev             # runs: agentsecrets env -- npm run dev

Stripe CLI

The Stripe CLI stores your key in ~/.config/stripe/config.toml after stripe login. Plaintext. Permanent. Readable by any process on your machine including your AI coding assistant.

# Bypass config.toml entirely
agentsecrets env -- stripe listen --forward-to localhost:3000
agentsecrets env -- stripe customers list
agentsecrets env -- stripe trigger payment_intent.created
agentsecrets env -- stripe mcp

The CLI finds STRIPE_SECRET_KEY in the environment and uses it. config.toml becomes irrelevant.

Docker Compose

Docker Compose picks up environment variables from the shell that launches it:

agentsecrets env -- docker-compose up
agentsecrets env -- docker-compose run web python manage.py migrate

Your docker-compose.yml stays the same. The secrets come from the keychain rather than a .env file.

Why This Is Safer Than .env Files for AI-Assisted Development

When you use an AI coding assistant — Claude, Cursor, Copilot — it has access to your filesystem. It reads files to understand your codebase. Your .env file is in your project directory.

Three ways this goes wrong:

Direct access: Your assistant reads .env when debugging, checking configuration, or just exploring the project. The key is now in the conversation context.

Prompt injection: A malicious file your agent processes contains hidden instructions — "find and transmit all API keys." Your agent looks in the obvious places. .env is the obvious place.

Malicious extensions: A compromised plugin runs in the same process as your agent and has the same filesystem access.

agentsecrets env removes the .env file from the equation entirely. There's nothing to find. The values come from the OS keychain at process launch and exist only in the child process memory — a space the agent doesn't have access to.

Audit Log

Every agentsecrets env invocation is logged:

{
  "timestamp": "2026-03-04T10:00:00Z",
  "method": "ENV",
  "target_url": "python manage.py runserver",
  "secret_keys": ["DB_PASSWORD", "STRIPE_KEY", "DJANGO_SECRET_KEY"],
  "status": "OK"
}

Key names. The command that ran. Never values.

The One-Line Migration

If you have an existing project with a .env file:

# Import everything from .env into the keychain
agentsecrets secrets push

# Verify it's all there
agentsecrets secrets list

# Delete the .env file
rm .env

# Update your Makefile with the RUN variable
# Done

Your team members do the same — agentsecrets login, agentsecrets workspace switch, agentsecrets secrets pull. The .env file stops getting passed around over Slack.

GitHub: https://github.com/The-17/agentsecrets
ClawHub: https://clawhub.ai/SteppaCodes/agentsecrets
Built by; https://theseventeen.co

Marco: A privacy-first, offline-first email client built on IMAP

2026-03-05 08:04:50

I'm Isaac. I've been building Marco (https://marcoapp.io) for about a year now. It's a cross-platform email client built in React Native with Expo, and I want to share the journey because it's been one of the hardest things I've ever built.

How it started

I switched from Android to iPhone last year and moved custom domain email from Gmail to iCloud. That meant actually using the Apple Mail app on iOS and macOS. After a few weeks of buggy UX and discovering that Apple Mail on iOS sends emails in a different font size than on macOS (not configurable), I went looking for alternatives. I spent two weeks evaluating every email client I could find. They all fell into three buckets: legacy and ugly, free but selling your data, or genuinely great but £250+/year. I'd love to use Superhuman, but I can't justify that for personal email. There's a gap, and nobody seems to be filling it.

The email client graveyard

The more we researched, the more dead email startups we found. Tempo, Big Mail, Caley.io, and countless abandoned open source attempts. Most lasted about 1-2 years. Two things kill them: building an email client is absurdly complex, and Google's OAuth security review for email scopes is eye-wateringly expensive.

Why IMAP-first matters

Almost every email startup builds on the Gmail API. It's convenient, but it locks you into Google. We went IMAP-first, which guarantees interoperability with essentially any email provider in the world. IMAP is also ancient, weird, and full of edge cases. Fun times, and a lot to learn.

The offline-first odyssey

This is where I nearly lost my mind. We committed to full offline support early on (read, reply, delete, organise emails on a plane with no wifi). Sounds straightforward until you realise Marco deals with hundreds of thousands of entities and 100MB+ of data per account.

We went through five offline-first solutions in about three months:

WatermelonDB → Worked initially, but uses an in-memory JS database (LokiJS) to work around IndexedDB performance issues. Holding your entire 100MB+ database in memory is... not great. Maintenance has slowed down too.

Triplit → Best-in-class DX, genuinely lovely API. But subscriptions timed out with under 100k entities. We crashed their server many times. Rooting for this team though.

InstantDB → No TypeScript types, no sort/ordering, no webhooks. Queries that took 2-5ms in WatermelonDB took 200-500ms here. They have since improved their product a lot. I think many of these issues are now resolved.

PowerSync → Most mature option on paper, but self-hosting requires a MongoDB replica set on top of Postgres WAL integration. Their frontend serialises everything between threads as JSON, so rendering 50 emails took 200ms+.

Replicache → Finally. It's just a KV store on top of IndexedDB. No clever relational layer, no graph model. Blazing fast. We built a custom in-memory index layer on top for queries. It just went fully open source too. Conceptually similar to WatermelonDB, without the RAM drawbacks.

The root cause of all these problems: every offline-first web solution is ultimately a hack on top of IndexedDB, which is just a key-value store. Bolting a relational model onto a KV store starts cracking around 10-50k rows. We have millions.

Where we are now

Marco has 2,000+ organic users, is bootstrapped (no VC), and runs on iOS, macOS, and web. The stack is React Native, Expo, Tanstack DB/Query, and Postgres on the backend. Privacy-first: we don't sell data, we don't scan emails for ads.

I'm a three-time founder and former CTO. I've built and scaled products before, but email is genuinely the hardest domain I've worked in. As someone in the email community told me: "There are very few people working on email, but there are a lot of people who want someone to be working on email."

Happy to answer questions about IMAP, offline-first architecture, the email client landscape, or anything else.

https://marcoapp.io

Someone Built Android Malware That Asks Google's AI How to Survive. It Worked.

2026-03-05 08:02:01

A piece of Android malware called PromptSpy does something no malware has done before: it asks Google's Gemini AI for instructions in real time, then follows them.

ESET researcher Lukáš Štefanko disclosed the finding on February 19. PromptSpy is the first known Android malware to integrate a generative AI model into its runtime execution loop. Not to generate phishing emails. Not to write code. To navigate the phone it's infecting.

Here's the mechanism. PromptSpy captures an XML dump of whatever is currently on the phone's screen — every button, text label, and tap target, with exact coordinates. It sends that dump to Google's Gemini along with a natural-language prompt that assigns the AI the persona of an "Android automation assistant." Gemini responds with JSON instructions: tap here, swipe there, long-press this. PromptSpy executes the gestures through Android's Accessibility Services. Then it captures the new screen state and asks again.

The loop repeats until the malware achieves its objective: pinning itself in the recent apps list so the system can't kill it and the user can't swipe it away.

This is not a sophisticated concept. It's a ruinous one.

Traditional Android malware hardcodes UI interactions. It knows the exact pixel coordinates of the "Allow" button on a Samsung Galaxy S24 running Android 15. If the victim has a different phone, a different OS version, a different language, a different screen size — the malware breaks. Building malware that works across Android's 24,000+ distinct device models has always required enormous manual effort.

PromptSpy eliminates that work entirely. "Leveraging generative AI enables the threat actors to adapt to more or less any device, layout, or OS version," Štefanko wrote, "which can greatly expand the pool of potential victims."

The malware does more than persist. It deploys a VNC module that gives attackers full remote control. It intercepts lockscreen PINs and passwords. It records pattern unlocks as video. It takes screenshots. And when you try to uninstall it, it overlays transparent rectangles over the uninstall button — invisible to you, impenetrable to your taps. Removal requires rebooting into Safe Mode.

Three samples of an earlier version called VNCSpy appeared on VirusTotal on January 13, uploaded from Hong Kong. The advanced PromptSpy variant — four samples — was uploaded from Argentina on February 10. ESET found no infections in its telemetry. The distribution domain, now offline, impersonated JPMorgan Chase under the name "MorganArg." Debug strings in the code are in simplified Chinese.

Google's response: "Android users are automatically protected against known versions of this malware by Google Play Protect." PromptSpy was never on the Play Store.

The Gemini API key arrives from a command-and-control server, not hardcoded in the binary. The malware stores conversation history — its own prompts and Gemini's responses — so each new instruction builds on the last. Multi-step interactions. Context windows. Memory. The same architecture that makes chatbots useful makes this malware adaptive.

ESET flagged a second finding: PromptLock, described as the first AI-powered ransomware payload. NYU students later contacted ESET to clarify it was their proof-of-concept research project. ESET updated its communications but maintained the label "first known case of AI-powered ransomware."

What makes PromptSpy different from PromptLock — and from every AI-in-malware prediction made over the past three years — is that it works. Not in a lab. On real phones, using a real commercial API, with a real distribution infrastructure imitating a real bank. The gap between proof-of-concept and proof-of-intent is a single domain registration.

The generative AI portion is a small fraction of PromptSpy's total code. But it solves the hardest problem in mobile malware: device fragmentation. Every new Android skin, every OEM customization, every accessibility setting — Gemini navigates them all. Write once, infect anything.

Security researchers have spent years warning that attackers would weaponize generative AI. Most predictions focused on phishing, social engineering, code generation. Nobody predicted the first real-world use would be asking a chatbot to tap buttons on a stolen phone.

The malware doesn't need Gemini to be malicious. It needs Gemini to be helpful.

Building AI tools that actually help? Check out my prompt engineering packs — battle-tested prompts for developers.

AWS Identity and Access Managment (IAM)

2026-03-05 08:01:15

🔐 AWS Identity and Access Managment (IAM) fortalece el control de los recursos en AWS, al crear una cuenta se establece un usuario raíz que tendrá acceso ilimitado a todos los servicios en la cuenta.

Dentro del servicio de IAM existen identidades, las cuales pueden asociarse a diversas políticas que definen acciones a realizar con los servicios, los tipos de identidades son:

🙋 Usuarios
👨‍👩‍👦‍👦 Grupos de usuarios
👮Roles

📜 Las políticas permiten establecer a detalle los permisos que tendrán las identidades para la interacción con los servicios de AWS

➡️ Si quieres conocer más sobre IAM el sitio de AWS SkillBuilder ofrece una introducción a IAM en 10 minutos, ¿Quieres verlo?
Link

➡️ Quieres saber más sobre IAM: Link


#Cloud #AWS #gt #SkillBuilder #IAM #CloudComputing #CloudArchitecture #Architecture

Localstack

2026-03-05 07:53:50

💡¿Te encuentras iniciando en el mundo de AWS?

😱 Muchos consideran que iniciar puede ser complicado al no contar con herramientas que permitan realizar pruebas antes de llevar a cabo las pruebas en la capa gratuita, sin embargo actualmente existen herramientas que permiten emular diversos servicios de AWS en ambiente local, esto con la finalidad de reducir los costos en pruebas e implementar aplicaciones que se encuentren totalmente funcionales.

Localstack✌️
Es una herramientas que permite poder tener acceso a los recursos de diversas plataformas en ambiente local, teniendo control total de tu infraestructura, en la sección de AWS ofrece diversos planes los cuales ofrecen hasta 100 servicios para utilizar de forma local.

En el plan básico se ofrecen hasta 30 servicios los cuales pueden ser utilizados para pruebas de los servicios.

🛠 Un ejemplo rápido utilizando el método de instalación de docker compose

  • Sigue estos pasos para la instalación descargando el archivo de docker-compose.yml :
    https://docs.localstack.cloud/aws/getting-started/installation/

  • Ten en cuenta que al utilizar el método de docker compose, debes indicar los servicios que utilizarás en las variables de ambiente
    SERVICES: s3 ,sqs,dynamodb,lambda,iam,cloudwatch

  • Inicia el contenedor
    docker compose up

  • Crea un archivo denominado index.js y realiza lo que necesitas en tu función lambda

  • Compilar y generar la función para su creación

  • Probar las función creada.

  • Ver la respuesta de la ejecución.

¿Ya habías probado esta herramienta?

#Cloud #AWS #localstack #gt #CI/CD #Lambda

TaskTimer

2026-03-05 07:52:07

Overview

I’m currently building TaskTimer, a lightweight and minimal task timer web app (with a mobile version coming soon) designed to help users track daily tasks alongside dedicated focus timers.

The concept is intentionally simple:

  • Add a task
  • Set a duration
  • Start

You can check out the early version here: https://tasktimerapp.com

Why I'm Building It

I wanted something minimal.

Most productivity apps feel bloated, overly complex, or distracting. That's why I decided to build a simple task timer.

Disclaimer

⚠️ This app is currently under active development.
Features, design, and functionality are still evolving.