Silkroad Innovation Hub’s Road to Battlefield competition continues
The Road to Battlefield competition is now in its second year, and its purpose is to give founders across Central Eurasia a direct route to Startup Battlefield
找到 139 篇相关文章
The Road to Battlefield competition is now in its second year, and its purpose is to give founders across Central Eurasia a direct route to Startup Battlefield
When I first connected my GitLab CI/CD pipelines to AWS, I used the simplest solution: an IAM user with an Access Key and Secret Access Key stored as GitLab CI/CD variables. It worked. But there was one problem: those credentials were permanent. They had to be stored, protected and eventually rotated. If they were accidentally exposed in logs or compromised, they could remain valid until manually revoked. I wanted a cleaner solution. So I replaced permanent AWS credentials with OIDC federation between GitLab and AWS . The result is simple: GitLab pipelines can access AWS without storing any permanent AWS credentials. In this post, I'll explain how I implemented it, how the authentication flow works, and one important issue I faced when using it with EKS and Terraform. The architecture The authentication flow looks like this: ┌──────────────┐ │ GitLab CI │ └──────┬───────┘ │ │ OIDC token ▼ ┌──────────────┐ │ AWS STS │ └──────┬───────┘ │ │ Temporary credentials ▼ ┌──────────────┐ │ IAM Role │ └──────┬───────┘ │ ├──────────► Terraform │ ├──────────► ECR │ └──────────► EKS Instead of GitLab storing an AWS Access Key, it proves its identity to AWS using a short-lived OIDC token. AWS verifies the token and returns temporary credentials. How does OIDC authentication work? The process can be summarized in five steps: GitLab creates an OIDC token for the CI/CD job. The pipeline sends this token to AWS. AWS verifies that the token really comes from GitLab. AWS checks that the project is allowed to assume the requested IAM role. AWS STS returns temporary credentials. These credentials expire automatically. So there is nothing permanent to store or rotate inside GitLab. Step 1 — Register GitLab as an OIDC provider AWS first needs to trust GitLab as an identity provider. I configured the OIDC provider using Terraform: data "tls_certificate" "gitlab" { url = "${var.gitlab_url}/.well-known/openid-configuration" } resource "aws_iam_openid_connect_provider" "gitlab" { url = var . gi
"Why not just use a cron job?" is the first question I get whenever someone sees an Airflow DAG. Fair question. Cron works. It's been around for decades. It's simple. The real answer isn't that cron is bad — it's that cron solves a different problem than Airflow does. Cron is a job scheduler . It runs a command at a fixed time. That's it. It doesn't know whether the command succeeded, whether its dependencies are satisfied, or whether it should even run at all today. It just fires the command and moves on. Airflow is a workflow orchestrator . It doesn't just schedule tasks — it models them as a graph of dependencies, tracks their state, retries failed ones, and gives you a UI to see what ran, what failed, and why. Here's where that difference actually matters. The problem cron can't solve Imagine a simple ETL pipeline: Extract raw data from an API Validate and clean it Load into a warehouse Run a transformation Send a Slack alert if anything fails With cron, you'd write five separate cron entries, one per step, and hope the timing works out. If step 2 fails but step 3 runs anyway, you now have bad data in your warehouse. If step 4 takes twice as long one day, you've silently broken your SLA. Nobody gets notified unless you manually add alerting logic to every script. With Airflow, you model this as a DAG: from airflow import DAG from airflow.operators.python import PythonOperator from datetime import datetime with DAG ( dag_id = " daily_etl " , schedule = " 0 6 * * * " , start_date = datetime ( 2026 , 1 , 1 ), catchup = False , ) as dag : extract = PythonOperator ( task_id = " extract " , python_callable = extract_data ) validate = PythonOperator ( task_id = " validate " , python_callable = validate_data ) load = PythonOperator ( task_id = " load " , python_callable = load_to_warehouse ) transform = PythonOperator ( task_id = " transform " , python_callable = run_transformation ) extract >> validate >> load >> transform Airflow guarantees the order. If validate fail
Picture a field technician standing in a basement with zero signal, trying to get an app to summarize a maintenance log and flag anything that looks like a safety issue. Or a language app that needs to correct pronunciation in real time, mid-commute, on a subway with no connectivity at all. A few years ago, both of those scenarios meant either building a degraded offline mode or just telling the user to try again later. Neither answer felt great. That's the actual reason on-device AI has become a real conversation in Android development in 2026, not because it's the trendy thing to bolt onto a feature list. Running inference locally solves specific, concrete problems: it keeps sensitive data off the network, it removes the round-trip latency of a cloud call, it works when there's no connectivity at all, and it gives you more predictable operating costs since you're not paying per-token for every user interaction. None of that means cloud AI is going away, and I'd be skeptical of anyone telling you it is. Most production apps in 2026 end up running a mix of both. But there's now a real, practical case for pushing certain workloads onto the device itself, and that's what this article is actually about - where local inference genuinely helps, where it falls short, and what it takes to build it properly in Kotlin. What Is On-Device AI? On-device AI means running a machine learning model directly on the user's phone, using the device's own CPU, GPU, or NPU, instead of sending a request to a server somewhere and waiting for a response. The model, or at least the parts of it needed for inference, lives on the device. Cloud AI still has the advantage in raw model size and reasoning depth - nobody's running a 70-billion-parameter model on a phone, at least not yet. But for narrower, well-defined tasks, on-device models have become genuinely capable, and the trade-offs are worth understanding side by side. Factor On-Device AI Cloud AI Inference location Runs on the user's dev
With protocol values and message framing complete, Stage 2 delivered the first end-to-end call: plaintext h2c unary RPC. This is already on main , and Stage 3 and Stage 4 subsequently completed all four RPC cardinalities on the same transport primitive. Previous: Building a Leak-Safe gRPC Frame Decoder on Reactor Netty Method Descriptor Is Where Protocol Meets Types A method requires a precise service name, method name, cardinality, and request/response marshallers: var echo = new GrpcMethod <>( "testing.EchoService" , "Echo" , GrpcMethod . Cardinality . UNARY , new ProtobufMarshaller <>( StringValue . parser ()), new ProtobufMarshaller <>( StringValue . parser ())); The generated path must be: /testing.EchoService/Echo The service registry matches by exact full path. An unknown path returns UNIMPLEMENTED ; registering the same path twice fails immediately when building the service definition. Server Validates Protocol Before Subscribing to Business Logic ReactorGrpcServer uses Reactor Netty h2c: DisposableServer bound = HttpServer . create () . host ( host ) . port ( port ) . protocol ( HttpProtocol . H2C ) . handle ( handler: : handle ) . bindNow ( Duration . ofSeconds ( 10 )); Incoming requests are validated in order: HTTP method must be POST; content-type must be application/grpc or application/grpc+... ; te must declare trailers; path must exist; currently only unary cardinality is allowed; metadata and message size must not exceed limits. Only after validation passes does it create a GrpcCallContext and subscribe to the request body, preventing invalid requests from entering the business handler. HTTP 200 Does Not Mean RPC Success The server writes a compatible content-type first; the final status comes from trailing headers: response . status ( 200 ) . header ( HttpHeaderNames . CONTENT_TYPE , "application/grpc+proto" ); response . trailerHeaders ( trailers -> { GrpcException error = terminal . get (); if ( error == null ) { writeStatus ( trailers , GrpcStatu
I've always found reading hard. Long documents slide off my attention, and I lose my place constantly. What I really wanted was something that would read to me and show me the words as it went — so my eyes and ears stayed in sync. Nothing did exactly that, so I built it. It's called ReadAloud , it's on Google Play, and this post is the "why" and the interesting bits of the "how." The moment it became real The first person I showed a rough build to was my Sister, Praise . She'd come to town to officiate a Women's Premier League match at Auntie Aku Astro Turf Park, and I pulled out my phone between everything else. She watched a paragraph read itself aloud with each word lighting up and got genuinely excited — that was the push I needed. She became tester #1. My colleague Reggie became tester #2. Between them they found the rough edges I'd stopped seeing, and the app settled into something stable. What it is A text-to-speech reader for PDFs, EPUB, DOCX, plain text and web articles . It reads aloud in natural voices, highlights each word as it speaks , and auto-scrolls to follow along. There's offline listening, English/French/Spanish, speed-reading (RSVP), a vocabulary builder, and reading stats. The stack: Kotlin, Jetpack Compose + Material 3, MVVM + Clean Architecture, Hilt, Room, DataStore, WorkManager , minSdk 26 . Now the parts that were actually interesting to build. 1. Word-by-word highlighting This is the whole product, so it had to be right. On-device voices are easy — Android's TextToSpeech gives you onRangeStart (API 26+), which fires per spoken range: override fun onRangeStart ( utteranceId : String , start : Int , end : Int , frame : Int ) { // highlight the substring [start, end) in the reader _currentRange . value = start to end } The catch: the natural cloud voices people actually want don't emit onRangeStart . So for cloud synthesis I wrap each word in an SSML <mark> and ask Google Cloud TTS to return timepoints : <speak><mark name= "w0" /> Every <mar
Open source WeatherNext model can make accurate predictions with lower-resolution weather data.
Indoor maps are often treated as a rendering problem: take a floor plan, extrude a few walls, and display the result. That is useful for a viewer, but it breaks down when a team needs to edit a real space, place assets, or hand the result to another application. We are building KiMap around a different boundary: turn a floor plan into an editable indoor scene in the browser, then keep the resulting structure useful for an SDK consumer. Why a floor plan is not enough A production indoor workflow needs more than a textured image on a plane. At minimum, the editor has to preserve the relationships between walls, floors, rooms, openings, and the objects placed in the space. Those relationships determine whether the result can later support navigation, facility workflows, a digital twin, or a custom web experience. That is why the current KiMap workflow starts with structure. You can define the indoor geometry, inspect it in 2D and 3D, and keep editing instead of committing to a static export too early. The browser editor boundary The editor is built with React and Three.js. The goal is not to replace every DCC tool. It is to make the early spatial workflow accessible to teams that need to test an indoor experience before investing in a full custom pipeline. The parts we are concentrating on are: editable floor-plan structure and bounded spaces 2D and 3D scene inspection in the same workflow reusable 3D furniture and local asset handling saving an indoor project without dropping the referenced model data a path toward SDK-oriented rendering and integration The last point matters. A scene that looks correct in an editor is not automatically useful to an application. We want the data boundary to be explicit enough that an SDK consumer can load the geometry and assets without rebuilding the scene from scratch. What we are testing next KiMap is in free early access. The most useful feedback is not generic interest; it is a concrete blocker from someone building an indoor-nav
The Silent Disruptor The silence in the room was absolute, broken only by the rhythmic scraping of pens on paper during a high-stakes meeting. Then, it happened. My pocket erupted into a frantic, brassy ringtone that seemed to last an eternity before I could fumble to silence it. My face turned crimson as the room’s focus shifted from the presentation to my vibrating trouser pocket. I had remembered to check my calendar, but I had completely forgotten to toggle my phone to silent mode. That moment of pure, concentrated embarrassment was the catalyst for me building Muffle. The Friction of Manual Control We live in an age of automation, yet our phones—the very devices meant to assist us—remain stubbornly manual when it comes to basic social etiquette. Every day, millions of people walk into mosques for prayer, classrooms for lectures, or medical offices for consultations, and every day, a percentage of them forget to silence their devices. This isn't just a minor annoyance; it is a persistent source of social friction. Before I started building Muffle, I looked for existing solutions. Most apps were either bloated with unnecessary permissions, required invasive cloud accounts, or simply failed to trigger at the right time. The fundamental problem wasn't just the lack of features like GPS-based prayer times or calendar-specific automation; it was the lack of reliability. If an automation app fails once, the user loses trust in it forever. If I am in a meeting, I cannot afford for the app to 'sleep' because the system decided to save battery at the expense of my configured routine. I needed something that could handle these state changes consistently, regardless of whether the phone was in my pocket, sitting on a desk, or buried in a bag. Architecting for Reliability When I began writing the core logic for Muffle, I immediately hit the wall that every Android developer eventually faces: Doze Mode. Android’s aggressive power management is designed to preserve battery by
I have two-factor authentication (2FA) enabled on most of my accounts using an authenticator app. Recently, while installing the app on another Android device, I tried to change the backup password, but it didn't work. As a result, I lost access, had to disable 2FA, and re-enable it using a different authenticator app. Setting up 2FA again wasn't a problem because I was still logged in to most of my accounts. However, I didn't have my GitLab recovery codes. GitLab offers only two ways to regain access: receiving a six-digit verification code via email or generating new recovery codes using an SSH key associated with the account. Receiving a verification code via email is the easiest way to recover your account, but having an SSH key can be incredibly useful when receiving an email verification code isn't an option. Whenever I configure GitLab in my local environment, I create an SSH key for authentication and commit signing, as I always sign commits in my repositories. I described this process in a previous article . Get New Recovery Codes Check the SSH keys on your machine: ls -la ~/.ssh Look for files named like id_rsa , or id_ed25519 . Run the following command to get new recovery codes: ssh -i ~/.ssh/id_ed25519 git@gitlab.com 2fa_recovery_codes Replace id_ed25519 with the name of your SSH key file. Copy one of the recovery codes Go to the sign in page Enter your username and password Provide the recovery code when prompted Now you're signed in! Disable 2FA and re-enable it—and don't forget to save your recovery codes somewhere safe this time.
It happened during a medical appointment. I was sitting in the quiet waiting room, my thoughts occupied by the upcoming consultation, when my phone erupted with a loud, aggressive ringtone. The entire room turned to look at me, and I fumbled to silence it, accidentally hitting the volume up button instead of the mute toggle in my panic. I felt that specific, burning embarrassment that comes from being the person who disrupts a quiet space. I realized then that I had spent years writing code for others, yet I couldn't solve my own basic problem of managing my phone's profile. We live in a world of constant notifications and persistent demands on our attention. The real friction isn't just that phones ring; it's that we are expected to remember to manually toggle settings in a dozen different contexts every single day. Whether it is a classroom, a house of worship, or a professional meeting, the human element of remembering to flip a switch is the point of failure. I wanted an app that handled this silently, without me having to open an interface or even think about the current state of my device. I needed a system that functioned as an extension of my environment rather than an additional task. Building Muffle required me to confront the reality of modern Android background execution. Initially, I thought a simple BroadcastReceiver listening for time changes or geofence triggers would suffice. I was wrong. As soon as the phone entered Doze mode—the power-saving state introduced in Android 6.0—my triggers would either be delayed significantly or killed entirely by the system’s restrictive task scheduler. I had to architect a solution that could survive these aggressive optimizations while remaining battery-efficient. The core of the application resides in a ForegroundService that maintains a persistent notification. While many developers avoid these because of the UI footprint, it is the only way to signal to the OS that your process is performing an essential, user-v
We just bumped four dependencies in the app. Here's what each one brings. implementation 'androidx.constraintlayout:constraintlayout:2.2.2' implementation platform ( 'com.google.firebase:firebase-bom:34.17.0' ) implementation 'io.intercom.android:intercom-sdk:18.6.0' implementation 'com.auth0.android:auth0:4.0.1' ConstraintLayout 2.2.2 The library's in maintenance mode now — Google's steering everyone toward Compose for new UI — so releases here are small, focused patches. This one carries forward a binary compatibility fix in constraintlayout-core that landed in the 2.2.x line. Firebase BoM 34.17.0 The BoM pins compatible versions across every Firebase library you pull in. This release lands close behind: Firebase AI Logic (17.14.0) — new factory methods exposing thoughtSignature / isThought on response parts, plus automatic function calling for LiveGenerativeModel Authentication (24.2.0) — fixed an auth timeout on dual-stack Wi-Fi, where long IPv6 timeouts were blocking IPv4 fallback Cloud Firestore (26.4.1) — now caches documents over 1MB by chunk-reading from local SQLite; fixed a debug-logging OOM caused by large payloads Cloud Messaging (25.1.1) — fixed a re-registration bug tied to Firebase installation ID changes Crashlytics (20.1.0) — on API 37+, fatal event reports now carry OOM/anomaly context from the ProfilingManager API Firebase Installations (19.1.2) — internal storage moved from SharedPreferences to DataStore Performance Monitoring (22.0.6) — fixed _app_start traces getting incorrectly suppressed on API 34+ SQL Connect (17.3.2) — several fixes to realtime query subscriptions around auth-token refresh and expiry Intercom Android SDK 18.6.0 Pinch-to-zoom, double-tap-to-zoom, and pan on full-screen image attachments Fixed an ANR during Intercom.initialize() caused by Keystore and persisted-identity reads blocking the calling thread Fixed the keyboard covering form fields in Canvas Kit sheets — IME insets are now handled correctly Fixed a crash from a nu
This tutorial builds a starter "Hello World" style agent using Kotlin and the native Kotlin version of the Agent Development Kit (ADK). The full sample project is available on GitHub: xbill9 / adk-hello-world-kotlin Kotlin ADK and MCP Hello World This project is a runnable Kotlin Agent Development Kit (ADK) demo. A Kotlin LlmAgent uses Gemini to decide when to call a greet tool discovered from a local Kotlin Model Context Protocol (MCP) server. The project has two Gradle modules: agent : the Kotlin ADK agent, Gemini model configuration, MCP toolset, and interactive ReplRunner ; server : the Ktor MCP server that exposes greet . Technology Stack Kotlin: 2.3.0 Kotlin ADK SDK: com.google.adk:google-adk-kotlin-core (v0.6.0) MCP Kotlin SDK: io.modelcontextprotocol:kotlin-sdk-jvm (v0.8.1) Ktor Framework: 3.0.0 (Netty, SSE, ContentNegotiation, CORS) JDK: Java 25 Build System: Gradle 9.2.1 (Kotlin DSL) Prerequisites Java 25 A Gemini Developer API key The Gradle wrapper is included. Configure Gemini Create the local environment file: cp .env.example .env Set GOOGLE_API_KEY in .env , then load it: source ./set_env.sh The file is ignored by Git. Run the Demo Start the Kotlin MCP server in one… View on GitHub What Is Kotlin? Kotlin is a modern, statically typed programming language created by JetBrains. It runs on the Java Virtual Machine (JVM), works alongside existing Java libraries, and is widely used for Android, backend, and multiplatform development. Static typing is especially useful when building agents. Agent configuration, tool schemas, and tool results can all be checked by the compiler before a prompt reaches the model. Installing Java This sample uses Java 25 . If Java is not installed, SDKMAN! is a convenient way to install and switch between JDK versions on Linux and macOS: Home | SDKMAN! the Software Development Kit Manager SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on most Unix based systems. sdkman.io After installing
Introduction Transitioning from GitLab’s centralized CI/CD pipeline structure to GitHub Actions presents a unique challenge for developers accustomed to GitLab’s modular approach. In GitLab, a central 'pipelines' repository acts as a single source of truth, referenced by individual projects via the include keyword. This mechanism eliminates duplication of CI/CD configurations, ensuring consistency and reducing maintenance overhead. However, GitHub Actions operates under a different paradigm, where workflows are typically defined within the .github/workflows directory of each repository. This disparity forces users to rethink how to achieve centralization without GitLab’s native include functionality. The core issue lies in GitHub’s scoping rules for reusable workflows. While GitHub supports uses to reference workflows from a central repository, these workflows must reside in a publicly accessible repository or the same repository. This constraint introduces versioning challenges , as changes to the central workflow can inadvertently break dependent projects if not managed carefully. For instance, updating a reusable workflow without tagging a stable version can lead to inconsistent behavior across projects, as GitHub defaults to using the latest commit. Another friction point is the lack of direct equivalence between GitLab’s include and GitHub’s uses . GitLab’s include allows for seamless integration of CI configurations, treating the included file as part of the local context. In contrast, GitHub’s uses references an external workflow, which operates in its own scope . This means inputs and outputs must be explicitly defined, increasing the complexity of migration. For example, a GitLab CI job that references a shared script might fail in GitHub Actions if the script relies on environment variables not passed through the uses interface. To address these challenges, developers must adopt a hybrid approach . Composite actions , which bundle multiple steps into a sin
We run a React app and an Angular admin panel at work. Same company, same brand, and on paper the same design. On screen it was a different story. The React button had a 6px radius; the Angular one had 4px. The focus rings were two slightly different blues. Nobody noticed until somebody did. And every time design changed a token, someone got to hand-port it into two codebases. Twice the work, and it still drifted. So I went looking for something that treated both frameworks as equals. The React kits don't speak Angular. The Angular ones don't share a look with anything on the React side. Nothing let me define the design once and have it show up, the same, in both. So I built bpdm/ui . One rule: the look lives in tokens I gave myself one hard rule: nothing about how a component looks is allowed to live inside the React or Angular code. Colour, spacing, radius, the easing on transitions, all of it sits in @bpdm/tokens as plain CSS variables, and both framework packages just read from there. The component owns structure, behaviour, and the accessibility plumbing. The look comes from the tokens. @import "tailwindcss" ; @import "@bpdm/tokens/tokens.css" ; Change one token and both frameworks move together. There's no "now go sync the Angular theme" step, because there's only one theme to sync. Four ship in the box (two light, two dark). Override the variables and you've re-skinned all of it. The same component, twice React: import { Button , Badge } from " @bpdm/ui " ; export function Example () { return ( < Button variant = "primary" > Get started < Badge appearance = "soft" > New </ Badge > </ Button > ); } Angular: import { Component } from " @angular/core " ; import { BpdmButton } from " @bpdm/ng " ; @ Component ({ selector : " app-root " , imports : [ BpdmButton ], template : `<button bpdmButton>Get started</button>` , }) export class App {} Same padding, same radius, same focus ring. The accessibility isn't literally shared code: Radix does that work on the React s
Elena van Engelen discusses how to eliminate serverless vendor lock-in without sacrificing native cloud capabilities. She explains how to structure FaaS applications using Clean Architecture, Spring Cloud Function, and Gradle modules to isolate business logic. Finally, she shares a live demo deploying portable Kotlin services across AWS and Azure using Terraform CDK for multi-cloud IaC. By Elena van Engelen
The most misunderstood part of JavaScript — finally explained with analogies, diagrams, and zero hand-waving. If you've ever wondered why setTimeout(fn, 0) doesn't actually run in 0 milliseconds, or why Promises always run before your setTimeout callbacks, or how Node.js handles 10,000 simultaneous users on a single thread — you're about to have several "aha!" moments in a row. Buckle up. ☕ 🎤 Let's Start With an Icebreaker Pop quiz: What is JavaScript? Here's the most famous answer, often attributed to Philip Roberts' legendary JSConf talk: "JavaScript is a single-threaded, non-blocking, asynchronous, concurrent language. It has a Call Stack, an Event Loop, a Callback Queue, and some other APIs." Sounds sophisticated, right? Now ask the V8 engine the same question: "I have a Call Stack and a Memory Heap. I genuinely have no idea what those other things are." 🤯 That's the first paradox. The very features that make JavaScript powerful — the Event Loop, the queues, the async magic — are not part of the JavaScript engine itself . They live somewhere else entirely. Let's find out where. 📦 Part 1: The Basics You Need to Know JavaScript is Single-Threaded At its core, JavaScript has exactly one main thread of execution . This is the Golden Rule : One Thread = One Call Stack = One thing at a time. The Call Stack is a data structure that tracks where you are in your code. When you call a function, it gets pushed onto the stack. When it returns, it gets popped off. It follows a LIFO (Last In, First Out) principle — like a stack of plates. function greet ( name ) { console . log ( `Hello, ${ name } !` ); } function main () { greet ( " Ahmed " ); } main (); // Call Stack (reading bottom to top): // [greet] ← currently running // [main] // [global] Simple, right? But what happens when JavaScript encounters a task that takes time? 🚫 Part 2: The Problem — Blocking Imagine JavaScript has to fetch data from an API. That might take 2 seconds. Or it has to read a huge file from disk.
The fast fix If your GitLab CI job fails with Cannot connect to the Docker daemon at unix:///var/run/docker.sock , your docker client is looking for a local socket that does not exist inside the job container, because DOCKER_HOST is not set. Point the client at the docker:dind service over TCP and the error goes away: build : image : docker:28.3 services : - name : docker:28.3-dind alias : docker variables : DOCKER_HOST : tcp://docker:2376 DOCKER_TLS_CERTDIR : " /certs" DOCKER_CERT_PATH : " /certs/client" DOCKER_TLS_VERIFY : " 1" script : - docker info - docker build -t my-app . That is the whole fix for the common case. The rest of this page explains why the socket variant of the error is different from the tcp://docker:2375 variant, and covers the two other setups (socket-mounted runners and the Kubernetes executor) where the same message shows up for a different reason. Why you get the unix socket variant specifically This error is not the same as Cannot connect to the Docker daemon at tcp://docker:2375 . The address in the message tells you exactly what the client tried: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? When DOCKER_HOST is empty, the Docker CLI falls back to its compiled-in default, the local unix socket at /var/run/docker.sock . Inside a GitLab CI job that uses the docker executor, that socket file simply is not there. The daemon runs in a separate docker:dind service container, not in your job container, so there is nothing listening on the local socket. The client connects, finds no socket, and prints the message above. The tcp://docker:2375 form is the opposite problem: DOCKER_HOST is set correctly but the dind service is not reachable (missing service, no privileged mode, or a TLS mismatch). If you are seeing that address instead, read the companion write-up on the tcp://docker:2375 form of this error , which walks the service and privileged-mode causes in detail. This page is about the case w
GitLab has introduced a new approach to Green DevOps, demonstrating how software engineering teams can measure the carbon emissions generated by their CI/CD pipelines. By Craig Risi
GitLab has released version 19.2 of its DevSecOps platform, adding agentic automation aimed at the security and review work that has piled up as AI coding tools generate more code than developers can check by hand. The release, announced on 16 July 2026, brings four features out of beta or into public beta: Dependency Scanning Auto-Remediation, Security Review Flow, GitLab Duo CLI and Custom Flows By Matt Saunders